c# - 是否可以在一个 ASP.NET MVC 应用程序中同时进行 Azure AD 和个人帐户身份验证?

标签 c# asp.net asp.net-mvc authentication azure

通过在 Startup.Auth.cs 文件中执行此操作,我取得了一定的成功

  // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.Properties["Microsoft.Owin.Security.Constants.DefaultSignInAsAuthenticationType"] = "ExternalCookie";

        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
             Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        app.UseOpenIdConnectAuthentication(
          new OpenIdConnectAuthenticationOptions
          {
              ClientId = clientId,
              Authority = authority,
              PostLogoutRedirectUri = postLogoutRedirectUri
          });

我面临的挑战是,当用户注销并尝试访问非登录页面时,例如 http://mywebsite/users/management而不是http://mywebsite/account/login应用程序自动重定向到 Azure AD 登录页面,这是不正确的。因为可能有些用户根本没有 Azure AD 帐户。即使我们在 AD 登录页面中提供正确的用户 ID 和密码并单击登录,它仍然会在 http://login.windows.net 内的不同 URL 之间进行重定向。并且根本不访问我们的网站。

这是注销代码 -

           AuthenticationManager.SignOut(new string[] { DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.ApplicationCookie, OpenIdConnectAuthenticationDefaults.AuthenticationType });
        return RedirectToAction("Login", "Account");

我不确定我在这里做错了什么。

编辑 1 我的ExternalLoginCallback方法

public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            return RedirectToAction("Login");
        }

        var claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.Sid, "Office365"));

        // Sign in the user with this external login provider if the user already has a login

        var user = await UserManager.FindByEmailAsync(loginInfo.ExternalIdentity.Name);

        if (user != null && user.IsActive == true && user.EmailConfirmed == true)
        {
            var result = await UserManager.AddLoginAsync(user.Id, loginInfo.Login);

            if (result.Succeeded)
            {
                if (claims != null)
                {
                    var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
                    userIdentity.AddClaims(claims);
                }
            }

            await SignInAsync(user, isPersistent: true);
            Session[AppConstants.General.UserID] = user.Id;

            string fullName = string.Format("{0} {1}",user.FirstName,user.LastName);
            Session[AppConstants.General.UserFullName] = fullName;

            return RedirectToLocal(returnUrl);
        }
        else
        {
            // If the user does not have an account, tell that to the user.
            ViewBag.ReturnUrl = returnUrl;
            ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
            return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
        }
    }

最佳答案

试试这个

app.UseOpenIdConnectAuthentication(
           new OpenIdConnectAuthenticationOptions
           {
               ClientId = ClientId,
               Authority = Authority,                   
               Notifications = new OpenIdConnectAuthenticationNotifications()
               {


                   RedirectToIdentityProvider = (context) =>
                   {

                       if (context.Request.Path.Value == "/Account/ExternalLogin" || (context.Request.Path.Value == "/Account/LogOff" && context.Request.User.Identity.IsExternalUser()))
                       {
                           // 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;
                       }
                       else
                       {
                           //This is to avoid being redirected to the microsoft login page when deep linking and not logged in 
                           context.State = Microsoft.Owin.Security.Notifications.NotificationResultState.Skipped;
                           context.HandleResponse();
                       }
                       return Task.FromResult(0);
                   },
               }
           });

编辑:

忘记了这个扩展方法

    public static class IdentityExtensions
{
    public static bool IsExternalUser(this IIdentity identity)
    {
        ClaimsIdentity ci = identity as ClaimsIdentity;

        if (ci != null && ci.IsAuthenticated == true)
        {
            var value = ci.FindFirstValue(ClaimTypes.Sid);
            if (value != null && value == "Office365")
            {
                return true;
            }
        }
        return false;
    }
}

编辑2:

您必须在ExternalLoginCallback(AccountController)中有一些自定义逻辑,例如添加 Sid 声明。在这种情况下,还有检查用户是否允许外部登录的逻辑。

 // GET: /Account/ExternalLoginCallback
    [AllowAnonymous]
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl, string urlHash)
    {
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            return RedirectToAction("Login");
        }

        var claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.Sid, "Office365"));

        // Sign in the user with this external login provider if the user already has a login
        var user = await UserManager.FindAsync(loginInfo.Login);
        if (user == null)
        {
            user = await UserManager.FindByNameAsync(loginInfo.DefaultUserName);

            if (user != null)
            {
                if(user.AllowExternalLogin == false)
                {
                    ModelState.AddModelError("", String.Format("User {0} not allowed to authenticate with Office 365.", loginInfo.DefaultUserName));
                    return View("Login");
                }
                var result = await UserManager.AddLoginAsync(user.Id, loginInfo.Login);

                if (result.Succeeded)
                {
                    if (claims != null)
                    {
                        var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
                        userIdentity.AddClaims(claims);
                    }
                    await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
                }
                return RedirectToLocal(returnUrl);
            }
            else
            {
                ModelState.AddModelError("", String.Format("User {0} not found.", loginInfo.DefaultUserName));
                return View("Login");
            }
        }
        else
        {

            if (user.AllowExternalLogin == false)
            {
                ModelState.AddModelError("", String.Format("User {0} not allowed to authenticate with Office 365.", loginInfo.DefaultUserName));
                return View("Login");
            }

            if (claims != null)
            {
                var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
                userIdentity.AddClaims(claims);
            }
            await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            return RedirectToLocal(returnUrl);
        }
    }

关于c# - 是否可以在一个 ASP.NET MVC 应用程序中同时进行 Azure AD 和个人帐户身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29006822/

相关文章:

c# - 找出哪个控件触发了回发

javascript - 从 JSON 加载数据表时出错

c# - InsertOrUpdate 为标识主列抛出错误

c# - 从 Xml 文件中检索一些数据

c# - 改进 LINQ 查询,使其完全在数据库中执行

c# - 使用 IIS 在本地主机上部署 Web 应用程序

c# - 从二进制文件中快速读取结构数组

c# - viewstate MAC 验证失败- '/' 应用程序中的服务器错误

c# - 检查var是否为String类型

c# - 子应用程序中的 Asp.net MVC Catchall 路由