是否有可能有一个ASP.NET MVC应用程序中都Azure的AD和个人账户验证? [英] Is it possible to have both Azure AD and Individual Account authentication in one ASP.NET MVC application?

查看:276
本文介绍了是否有可能有一个ASP.NET MVC应用程序中都Azure的AD和个人账户验证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是通过在Startup.Auth.cs做这个文件类型的成功

  //配置数据库环境和用户管理使用每个请求的单个实例
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext< ApplicationUserManager>(ApplicationUserManager.Create);
        app.Properties [Microsoft.Owin.Security.Constants.DefaultSignInAsAuthenticationType] =ExternalCookie;        //配置在cookie中的标志
        app.UseCookieAuthentication(新CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
             供应商=新CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity< ApplicationUserManager,ApplicationUser>(
                    validateInterval:TimeSpan.FromMinutes(30),
                    regenerateIdentity:(经理,用户)=> user.GenerateUserIdentityAsync(经理))
            }
        });        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);        app.UseOpenIdConnectAuthentication(
          新OpenIdConnectAuthenticationOptions
          {
              客户端Id =客户端ID,
              管理局=权威,
              PostLogoutRedirectUri = postLogoutRedirectUri
          });

我的挑战是,当用户登录时,并试图打好比说 HTTP非登录页面: // mywebsite /用户/管理而不是的http:// mywebsite /帐号/登录应用重定向自动在Azure AD登录页面,这是不对的。因为可能有没有帐户在Azure AD谁的所有用户。即使我们给在页面的广告我一个正确的用户名和密码,点击登录,它使不同的URL重定向间内 HTTP ://login.windows.net 以及从来就没有到我们的网站在所有

下面是注销code -

  AuthenticationManager.SignOut(新的String [] {DefaultAuthenticationTypes.ExternalCookie,DefaultAuthenticationTypes.ApplicationCookie,OpenIdConnectAuthenticationDefaults.AuthenticationType});
        返回RedirectToAction(登录,帐户);

我不知道我在做什么错在这里。

修改1
我ExternalLoginCallback方法

 公共异步任务<&的ActionResult GT; ExternalLoginCallback(字符串RETURNURL)
    {
        VAR LOGININFO =等待AuthenticationManager.GetExternalLoginInfoAsync();
        如果(LOGININFO == NULL)
        {
            返回RedirectToAction(登录);
        }        VAR索赔=新的List<权利要求GT;();
        claims.Add(新索赔(ClaimTypes.Sid​​Office365));        // SIGN在这个外部登录提供用户,如果用户已经有一个登录        VAR用户=等待UserManager.FindByEmailAsync(loginInfo.ExternalIdentity.Name);        如果(用户= NULL和放大器;!&安培; user.IsActive ==真放;&安培; user.EmailConfirmed == true)而
        {
            VAR的结果=等待UserManager.AddLoginAsync(user.Id,loginInfo.Login);            如果(result.Succeeded)
            {
                如果(索赔!= NULL)
                {
                    VAR的UserIdentity =等待user.GenerateUserIdentityAsync(的UserManager);
                    userIdentity.AddClaims(索赔);
                }
            }            等待SignInAsync(用户,isPersistent:真正的);
            会话[AppConstants.General.UserID] = user.Id;            字符串全名=的String.Format({0} {1},user.FirstName,user.LastName);
            会话[AppConstants.General.UserFullName] =全名;            返回RedirectToLocal(RETURNURL);
        }
        其他
        {
            //如果用户没有一个帐户,告诉给使用者。
            ViewBag.ReturnUrl = RETURNURL;
            ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
            返回视图(ExternalLoginConfirmation,新ExternalLoginConfirmationViewModel {电子邮件= loginInfo.Email});
        }
    }


解决方案

试试这个

  app.UseOpenIdConnectAuthentication(
           新OpenIdConnectAuthenticationOptions
           {
               客户端Id =客户端ID,
               管理局=管理局
               通知=新OpenIdConnectAuthenticationNotifications()
               {
                   RedirectToIdentityProvider =(上下文)=>
                   {                       如果(context.Request.Path.Value ==/帐号/ ExternalLogin||(context.Request.Path.Value ==/帐号/注销&放大器;&安培; context.Request.User.Identity.IsExternalUser() ))
                       {
                           //这确保了使用的地址进行登录和注销从请求动态回升
                           //这使您可以部署应用程序(以Azure网站,例如),而无需更改设置
                           //记住,这里使用的地址的基本URL必须Azure的AD预先置备。
                           字符串appBaseUrl = context.Request.Scheme +://+ context.Request.Host + context.Request.PathBase;
                           context.ProtocolMessage.RedirectUri = appBaseUrl +/;
                           context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
                       }
                       其他
                       {
                           //这是为了避免被重定向到Microsoft登录页面时,深层链接,而不是在登录
                           context.State = Microsoft.Owin.Security.Notifications.NotificationResultState.Skipped;
                           context.HandleResponse();
                       }
                       返回Task.FromResult(0);
                   },
               }
           });

编辑:

忘记了这个扩展方法

 公共静态类IdentityExtensions
{
    公共静态布尔IsExternalUser(此的IIdentity身份)
    {
        ClaimsIdentity CI =身份ClaimsIdentity;        如果(CI = NULL&放大器;!&安培; ci.IsAuthenticated == true)而
        {
            VAR值= ci.FindFirstValue(ClaimTypes.Sid​​);
            如果(值= NULL&放大器;!&安培;价值==Office365)
            {
                返回true;
            }
        }
        返回false;
    }
}

编辑2:

您必须有在ExternalLoginCallback(的AccountController)一些自定义逻辑,例如添加希德索赔。在这种情况下,也有逻辑来检查用户是否允许外部登录

  // GET:/帐号/ ExternalLoginCallback
    [使用AllowAnonymous]
    公共异步任务<&的ActionResult GT; ExternalLoginCallback(字符串RETURNURL,串urlHash)
    {
        VAR LOGININFO =等待AuthenticationManager.GetExternalLoginInfoAsync();
        如果(LOGININFO == NULL)
        {
            返回RedirectToAction(登录);
        }        VAR索赔=新的List<权利要求GT;();
        claims.Add(新索赔(ClaimTypes.Sid​​Office365));        // SIGN在这个外部登录提供用户,如果用户已经有一个登录
        VAR用户=等待UserManager.FindAsync(loginInfo.Login);
        如果(用户== NULL)
        {
            用户=等待UserManager.FindByNameAsync(loginInfo.DefaultUserName);            如果(用户!= NULL)
            {
                如果(user.AllowExternalLogin == FALSE)
                {
                    ModelState.AddModelError(,的String.Format(用户{0}不允许使用Office 365进行身份验证,loginInfo.DefaultUserName));
                    返回视图(登录);
                }
                VAR的结果=等待UserManager.AddLoginAsync(user.Id,loginInfo.Login);                如果(result.Succeeded)
                {
                    如果(索赔!= NULL)
                    {
                        VAR的UserIdentity =等待user.GenerateUserIdentityAsync(的UserManager);
                        userIdentity.AddClaims(索赔);
                    }
                    等待SignInManager.SignInAsync(用户,isPersistent:假的,rememberBrowser:假);
                }
                返回RedirectToLocal(RETURNURL);
            }
            其他
            {
                ModelState.AddModelError(,的String.Format(用户{0}未找到,loginInfo.DefaultUserName));
                返回视图(登录);
            }
        }
        其他
        {            如果(user.AllowExternalLogin == FALSE)
            {
                ModelState.AddModelError(,的String.Format(用户{0}不允许使用Office 365进行身份验证,loginInfo.DefaultUserName));
                返回视图(登录);
            }            如果(索赔!= NULL)
            {
                VAR的UserIdentity =等待user.GenerateUserIdentityAsync(的UserManager);
                userIdentity.AddClaims(索赔);
            }
            等待SignInManager.SignInAsync(用户,isPersistent:假的,rememberBrowser:假);
            返回RedirectToLocal(RETURNURL);
        }
    }

I am kind of successful by doing this in the Startup.Auth.cs file

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

The challenge I have is, when a user is signed out,and tries to hit a non-login page like say http://mywebsite/users/management rather than http://mywebsite/account/login the application redirects to the Azure AD sign-in page automatically, which is not right. Because there could be users who do not have account on Azure AD at all. Even if we give a proper userid and password in the AD sign in page and click sign-in, it keeps redirecting between different urls within http://login.windows.net and never goes to our website at all.

Here is the logout code -

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

I am not sure what I'm doing wrong here.

Edit 1 My ExternalLoginCallback method

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

解决方案

Try this

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

EDIT:

Forgot this extension method

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

EDIT 2:

You have to have some custom logic in the ExternalLoginCallback (AccountController) e.g. add the Sid claim. In this case there is also logic to check if the user allows external login.

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

这篇关于是否有可能有一个ASP.NET MVC应用程序中都Azure的AD和个人账户验证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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