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

时间:2016-08-22 19:36:58

标签: c# asp.net azure asp.net-identity azure-active-directory

我已经搞砸了几天了......

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

基本上Azure AD只是确认它们是组织的一部分,ASP.NET Identity部分是它自己的数据库,我可以使用[Authorize]属性在Azure AD外部设置自定义角色。 / p>

这是我的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))
            },
        });
    }

现在,当我执行HttpContext.Request.IsAuthenticated时,ASP.NET身份正在接管,这很好,我只需要一种方法来检查OpenID部分是否经过身份验证,所以我可以输入我的自定义逻辑来自动为用户签名。

1 个答案:

答案 0 :(得分:3)

知道了!

我最大的问题是尝试使用OWIN中间件为我做一切。 Azure AD的简单身份验证不需要OpenID中间件。我基本上在帐户控制器中创建了一个OpenIdAuth方法,该方法充当我的中间人,以便在用户访问网站之前对用户进行身份验证。

[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);
    }
}

令人敬畏的部分是当用户成功登录时Microsoft将传递的code变量。 (如记录Here)我使用相同的控制器方法并检查它是否为null但技术上可以使用两种不同的控制器方法(Microsoft将重定向回您为redirect_uri参数指定的URL)。

获得授权码后,我可以使用AuthorizationContext nuget包中的Microsoft.IdentityModel.Clients.ActiveDirectory来呼叫:AcquireTokenByAuthorizationCode。最后一个参数是资源URI。我使用的是图表资源,但您可以使用您在Azure管理门户中获得应用访问权限的任何其他资源。

最后,我的ConfigureAuth方法又回到了原来的问题。 ASP.NET身份版本:

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))
            },
        });
    }