仅将Azure AD用于身份验证而不将其用于授权 [英] Use Azure AD only for Authentication and not Authorization

查看:99
本文介绍了仅将Azure AD用于身份验证而不将其用于授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经为此困扰了几天...

I've been messing with this for a few days now...

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

What I would like to do is Authenticate users with Azure AD, and when successful, automatically log them in using ASP.NET Identity for authorization. If they do not have an account I would like to create one automatically.

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

Essentially Azure AD is just confirming that they are a part of the organization, the ASP.NET Identity portion is it's own database where I can use the [Authorize] attribute to set up custom roles OUTSIDE of 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))
            },
        });
    }

现在,当我执行HttpContext.Request.IsAuthenticated时,ASP.NET身份正在接管,我只需要一种方法来检查OpenID部分是否已通过身份验证,所以我可以按照我的自定义逻辑自动登录用户.

Right now the ASP.NET Identity is taking over when I do a HttpContext.Request.IsAuthenticated which is okay, I just need a way to check if the OpenID portion is authenticated or not so I can put in my custom logic to automatically sign the user in.

推荐答案

知道了!

我最大的问题是尝试使用OWIN中间件为我做所有事情.无需OpenID中间件即可对Azure AD进行简单身份验证.我实质上是在Account控制器中创建了一个OpenIdAuth方法,该方法用作我之间的一种方法,以便在用户有权访问该网站之前向Azure对其进行身份验证.

My biggest problem was attempting to use the OWIN middleware to do everything for me. The OpenID middleware is not needed for simple authentication to Azure AD. I essentially created a OpenIdAuth method in the Account controller which acts as my in-between to authenticate the user with Azure before they have access to the site.

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

最棒的部分是code变量,当用户成功登录时,Microsoft将传递该变量. (如此处所述)使用相同的控制器方法并检查其是否为null,但从技术上讲,可以使用两种不同的控制器方法(Microsoft将重定向回您为redirect_uri参数指定的url).

The awesome part is the code variable that will be passed by Microsoft when the user logs in successfully. (As documented Here) I used the same controller method and checked if it was null but technically two different controller methods can be used (Microsoft will redirect back to the url you specify for the redirect_uri parameter).

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

After I got the authorization code I can use the AuthorizationContext from the Microsoft.IdentityModel.Clients.ActiveDirectory nuget package to call: AcquireTokenByAuthorizationCode. The last parameter is the Resource URI. I'm using the Graph Resource but you can use any other resource that you've given your app access to in the Azure Management Portal.

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

Finally my ConfigureAuth Method is back to the plain ol' ASP.NET Identity version:

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

这篇关于仅将Azure AD用于身份验证而不将其用于授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆