仅将 Azure AD 用于身份验证而非授权

Ada*_*ley 3 c# asp.net azure asp.net-identity azure-active-directory

我已经被这个问题困扰了几天了...

我想做的是使用 Azure AD 对用户进行身份验证,成功后,使用 ASP.NET Identity 自动登录以进行授权。如果他们没有帐户,我想自动创建一个。

本质上,Azure AD 只是确认它们是组织的一部分,ASP.NET 标识部分是它自己的数据库,我可以在其中使用该[Authorize]属性设置 Azure AD 之外的自定义角色。

这是我的ConfigureAuth()方法:

public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(IntranetApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = SettingsHelper.ClientId,
                Authority = SettingsHelper.Authority,

                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
                    AuthorizationCodeReceived = (context) =>
                    {
                        var code = context.Code;
                        ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey);
                        String signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

                        AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
                        AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);

                        return Task.FromResult(0);
                    },
                    RedirectToIdentityProvider = (context) =>
                    {
                        // This ensures that the address used for sign in and sign out is picked up dynamically from the request
                        // this allows you to deploy your app (to Azure Web Sites, for example)without having to change settings
                        // Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
                        string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
                        context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
                        context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;

                        return Task.FromResult(0);
                    },
                    AuthenticationFailed = (context) =>
                    {
                        // Suppress the exception if you don't want to see the error
                        context.HandleResponse();
                        return Task.FromResult(0);
                    }
                }

            });

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            },
        });
    }
Run Code Online (Sandbox Code Playgroud)

现在 ASP.NET Identity 正在接管,当我做一个HttpContext.Request.IsAuthenticated可以的时候,我只需要一种方法来检查 OpenID 部分是否经过身份验证,以便我可以放入我的自定义逻辑来自动登录用户。

Ada*_*ley 5

知道了!

我最大的问题是试图使用 OWIN 中间件为我做所有事情。对 Azure AD 的简单身份验证不需要 OpenID 中间件。我基本上OpenIdAuth在 Account 控制器中创建了一个方法,它充当我的中间人,在用户访问站点之前使用 Azure 对用户进行身份验证。

[AllowAnonymous]
public ActionResult OpenIdAuth(string code)
{
    string clientId = "00000000-0000-0000-0000-000000000000"; // Client ID found in the Azure AD Application
    string appKey = "111111111112222222222223333333333AAABBBCCC="; // Key generated in the Azure AD Appliction

    if (code != null)
    {
        string commonAuthority = "https://login.windows.net/<TENANT_URL>";  // Eg. https://login.windows.net/MyDevSite.onmicrosoft.com
        var authContext = new AuthenticationContext(commonAuthority);
        ClientCredential credential = new ClientCredential(clientId, appKey);
        AuthenticationResult authenticationResult = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Request.Url.GetLeftPart(UriPartial.Path)), credential, "https://graph.windows.net");

        var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var signInManager = HttpContext.GetOwinContext().Get<ApplicationSignInManager>();

        var user = UserManager.FindByName(authenticationResult.UserInfo.UniqueId);
        if (user != null)
        {
            signInManager.SignIn(user, false, false);
        }
        else
        {
            var newUser = new ApplicationUser { UserName = authenticationResult.UserInfo.UniqueId, Email = authenticationResult.UserInfo.DisplayableId };
            var creationResult = UserManager.Create(newUser);

            if (creationResult.Succeeded)
            {
                user = UserManager.FindByName(newUser.UserName);
                signInManager.SignIn(user, false, false);
            }
            else
            {
                return new ViewResult { ViewName = "Error" };
            }
        }

        return Redirect("/");
    }
    else
    {
        var url = new Uri($"https://login.microsoftonline.com/<TENANT_URL>/oauth2/authorize?client_id={clientId}&response_type=code&redirect_uri=https://localhost/Account/OpenIdAuth");
        return Redirect(url.AbsoluteUri);
    }
}
Run Code Online (Sandbox Code Playgroud)

令人敬畏的部分是code当用户成功登录时 Microsoft 将传递的变量。(如记录在这里)我用同样的控制器方法,并检查它是否为空,但可用于技术上两种不同的控制器方法(微软将回重定向到您指定的URLredirect_uri参数)。

之后我得到了授权码,我可以使用AuthorizationContextMicrosoft.IdentityModel.Clients.ActiveDirectoryNuGet包来调用:AcquireTokenByAuthorizationCode。最后一个参数是资源 URI。我使用的是图形资源,但你可以使用在 Azure 管理门户中授予应用访问权限的任何其他资源。

最后,我的ConfigureAuth方法又回到了普通的 ASP.NET Identity 版本:

public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(IntranetApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            },
        });
    }
Run Code Online (Sandbox Code Playgroud)