ASP.NET MVC标识 - 一起使用内部用户和Azure AD身份验证

时间:2017-07-07 21:23:49

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

我们已经运行了通过令牌身份验证使用内部用户的ASP.NET MVC Web应用程序。这是以ASP.NET MVC模板提供的标准方式实现的。

现在,我们需要扩展此身份验证模型,并允许外部Azure AD用户登录配置租户的Web应用程序。我已经找到了Azure AD方面的所有内容。感谢microsoft github示例here

现在,个人帐户身份验证 Azure AD 都可以独立运行。但它没有合作。当我将两个中间件一起插入其给出问题时。

这是我的startup_auth.cs文件。

public partial class Startup
    {

        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);


            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });            
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);


            string ClientId = ConfigurationManager.AppSettings["ida:ClientID"];            
            string Authority = "https://login.microsoftonline.com/common/";

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = ClientId,
                Authority = Authority,
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
                {                        
                    ValidateIssuer = false,
                },
                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    RedirectToIdentityProvider = (context) =>
                    {                            
                        string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;                         
                        context.ProtocolMessage.RedirectUri = appBaseUrl;
                        context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
                        return Task.FromResult(0);
                    },                        
                    SecurityTokenValidated = (context) =>
                    {
                        // retriever caller data from the incoming principal
                        string issuer = context.AuthenticationTicket.Identity.FindFirst("iss").Value;
                        string UPN = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value;
                        string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

                        if (
                            // the caller comes from an admin-consented, recorded issuer
                            (db.Tenants.FirstOrDefault(a => ((a.IssValue == issuer) && (a.AdminConsented))) == null)
                            // the caller is recorded in the db of users who went through the individual onboardoing
                            && (db.Users.FirstOrDefault(b =>((b.UPN == UPN) && (b.TenantID == tenantID))) == null)
                            )
                            // the caller was neither from a trusted issuer or a registered user - throw to block the authentication flow
                            throw new SecurityTokenValidationException();                            
                        return Task.FromResult(0);
                    },
                    AuthenticationFailed = (context) =>
                    {
                        context.OwinContext.Response.Redirect("/Home/Error?message=" + context.Exception.Message);
                        context.HandleResponse(); // Suppress the exception
                        return Task.FromResult(0);
                    }
                }
            });

        }
    }

此配置适用于本地用户帐户,但不适用于AAD。要启用AAD身份验证,我需要配置UseCookieAuthentication部分,如下所示。这将破坏我的本地用户帐户身份验证。

  

app.UseCookieAuthentication(new CookieAuthenticationOptions {});

基本上我需要删除本地用户的中间件以使AAD工作。

我的意思是AAD没有工作,我无法进行任何受[Authoroze]属性保护的安全行动。它的调用事件SecurityTokenValidated,我能够获得所有AAD声明,并能够验证我的自定义租户。但只有在最后我重定向到我的应用程序的root,这是安全的操作,它扔回我的自定义登录页面。似乎它没有在内部登录用户,也没有创建必要的身份验证cookie。

我很感激我在这里可能缺少的任何想法。

由于

2 个答案:

答案 0 :(得分:1)

要支持来自社交数据提供者的个人帐户和其他帐户,只需使用OWIN组件添加它们。

要注销从Azure AD登录的用户,我们需要注销从Web应用程序和Azure AD发布的cookie。首先,我修改了ApplicationUser类以添加自定义声明,以检测用户是从Azure AD登录还是从以下各个帐户登录。

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        if((this.Logins as System.Collections.Generic.List<IdentityUserLogin>).Count>0)
            userIdentity.AddClaim(new Claim("idp", (this.Logins as System.Collections.Generic.List<IdentityUserLogin>)[0].LoginProvider));
        return userIdentity;
    }
}

然后我们可以更改LogOff方法以支持从Azure AD注销以清除Azure AD中的Cookie:

// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{

    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

    var idpClaim = ClaimsPrincipal.Current.Claims.FirstOrDefault(claim => { return claim.Type == "idp"; });
    if (idpClaim!=null)
        HttpContext.GetOwinContext().Authentication.SignOut(
            OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);

    return RedirectToAction("Index", "Home");
}

答案 1 :(得分:0)

听起来您的OpenID Connect身份验证未连接到您的Cookie身份验证。您似乎需要在SignInAsAuthenticationType中指定与OpenIdConnectAuthenticationOptionsAuthenticationType身份验证类型中的CookieAuthenticationOptions匹配的ExternalCookie