是否可以在一个ASP.NET MVC应用程序中同时具有Azure AD和个人帐户身份validation?

通过在Startup.Auth.cs文件中执行此操作,我有点成功

// Configure the db context and user manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(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( 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 ExternalLoginCallback(string returnUrl) { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { return RedirectToAction("Login"); } var claims = new List(); 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 ExternalLoginCallback(string returnUrl, string urlHash) { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { return RedirectToAction("Login"); } var claims = new List(); 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); } }