2015-03-12 9 views
9

Jestem rodzaju sukces robiąc to w Startup.Auth.cs złożyćCzy możliwe jest posiadanie uwierzytelnienia Azure AD i konta indywidualnego w jednej aplikacji MVC ASP.NET?

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

Wyzwaniem mam jest, gdy użytkownik jest wylogowany, i próbuje uderzyć stronę bez logowania jak powiedzieć http://mywebsite/users/management zamiast http://mywebsite/account/login aplikacja automatycznie przekierowuje na stronę logowania Azure AD, co nie jest poprawne. Ponieważ mogą istnieć użytkownicy, którzy nie mają konta w usłudze Azure AD. Nawet jeśli podamy prawidłowy identyfikator użytkownika i hasło na stronie logowania AD i klikniemy logowanie, będzie on nadal przekierowywał między różnymi adresami URL pod numerem http://login.windows.net i nigdy nie trafi na naszą stronę.

Oto kod wylogowania -

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

Nie jestem pewien, co robię źle tutaj.

Edycja 1 Moja metoda 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 }); 
     } 
    } 

Odpowiedz

8

Spróbuj

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:

pamiętasz tę metodę rozszerzenia

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:

Musisz mieć niestandardową logikę w ExternalLoginCallback (AccountController) np. dodaj roszczenie Sid. W tym przypadku istnieje również logika, aby sprawdzić, czy użytkownik zezwala na logowanie zewnętrzne.

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

próbowałem tego, ale dla mnie „wartość” zmienna ma wartość null, gdy zewnętrzna użytkownik loguje się. Czy to z powodu mojej drugiej app.UseCookieAuthentication() ustawienie? Zasadniczo zastąpiłem moją aplikację. UseOpenIdConnectAuthentication() ze swoim i zatrzymaj resztę. Czy to jest poprawne? –

+0

Masz rację. Sprawdź EDIT 2 w odpowiedzi. Możesz oczywiście uprościć funkcję ExternalLoginCallback, jeśli chcesz –

+0

Próbowałem, ale otrzymuję null na tej linii - 'code' var value = ci.FindFirstValue (System.Security.Claims.ClaimTypes.Sid); –

Powiązane problemy