2015-03-12 9 views
9

Sono genere di successo in questo modo nelle file di Startup.Auth.csÈ possibile avere sia l'autenticazione di Azure AD che l'account individuale in un'applicazione ASP.NET MVC?

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

La sfida che ho è, quando un utente è disconnesso, e cerca di colpire una pagina non di login come dire http://mywebsite/users/management anziché http://mywebsite/account/login, l'applicazione reindirizza automaticamente alla pagina di accesso di Azure AD, il che non è corretto. Perché potrebbero esserci utenti che non hanno alcun account su Azure AD. Anche se forniamo un ID utente e una password corretti nella pagina di accesso AD e facciamo clic su accesso, continua a reindirizzare tra diversi URL all'interno di http://login.windows.net e non viene mai inviato al nostro sito web.

Ecco il codice di logout -

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

io non sono sicuro di quello che sto facendo male qui.

Modifica 1 Il mio metodo 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 }); 
     } 
    } 

risposta

8

Prova questa

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:

dimenticato questo metodo di estensione

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

MODIFICA 2:

È necessario disporre di una logica personalizzata in ExternalLoginCallback (AccountController) ad es. aggiungi la rivendicazione Sid. In questo caso c'è anche la logica per verificare se l'utente consente il login esterno.

// 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

Ho provato a farlo, ma per me il "valore" variabile è nulla quando un utente accede esterni. E 'questo a causa della mia altra impostazione app.UseCookieAuthentication()? Fondamentalmente, ho sostituito la mia app. UseOpenIdConnectAuthentication() con il tuo e mantenuto il resto lì. È giusto? –

+0

Hai ragione. Controlla l'EDIT 2 nella risposta. È possibile semplificare la funzione ExternalLoginCallback se si desidera che sia –

+0

Provato, ma ottengo null su questa riga - 'code' var value = ci.FindFirstValue (System.Security.Claims.ClaimTypes.Sid); –

Problemi correlati