2014-10-23 5 views
10

Sto cercando di reindirizzare utente alla pagina in base al loro ruolo,ASP.NET MVC 5 Identità 2 Login reindirizzamento in base al ruolo dell'utente

Questa è l'implementazione predefinita della funzione di accesso che vengono con ASP.NET MVC 5 :

[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) 
{ 
    if (ModelState.IsValid) 
    { 
     var user = await UserManager.FindAsync(model.UserName, model.Password); 
     if (user != null) 
     { 
      await SignInAsync(user, model.RememberMe); 
      return RedirectToLocal(returnUrl); 
     } 
     else 
     { 
      ModelState.AddModelError("", "Invalid username or password."); 
     } 
    } 

    // If we got this far, something failed, redisplay form 
    return View(model); 
} 

private ActionResult RedirectToLocal(string returnUrl) 
{ 
    if (Url.IsLocalUrl(returnUrl)) 
    { 
     return Redirect(returnUrl); 
    } 
    else 
    { 
     return RedirectToAction("Index", "Employer"); 
    } 
} 

voglio essere in grado di reindirizzare utenti in base al loro ruolo, ho cercato di fare in questo modo:

[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) 
{ 
    if (ModelState.IsValid) 
    { 
     var user = await UserManager.FindAsync(model.UserName, model.Password); 
     if (user != null) 
     { 
      await SignInAsync(user, model.RememberMe); 

      //role Employer go to Employer page 
      if (UserManager.IsInRole(user.Id, "Employer")) 
      { 
       return RedirectToAction("Index", "Employer"); 
      } 
      //role Admin go to Admin page 
      else if (UserManager.IsInRole(user.Id, "Admin")) 
      { 
       return RedirectToAction("Index", "Admin"); 
      } 
      else 
      { 
       //no role 
       return RedirectToAction("Index", "Home"); 
      } 
     } 
     else 
     { 
      ModelState.AddModelError("", "Invalid username or password."); 
     } 
    } 

    // If we got this far, something failed, redisplay form 
    return View(model); 
} 

Ma c'è un problema, anche se il sito mi reindirizza a th La pagina corretta, Se navigo digitando l'url foo.com/admin quando non sono connesso con un account amministratore, il sito mi porta alla pagina di accesso con url foo.com/Account/Login?ReturnUrl=%2Fadmin , che è il comportamento previsto.

se effettuo il login con un account del datore di lavoro a questo punto, mi reindirizzerà alla pagina del datore di lavoro e mi collegherò come datore di lavoro, il che non è sbagliato, ma non dovrebbe essere il caso, il sito dovrebbe menzionare Dovrei effettuare il login con un account amministratore perché l'URL di ritorno è "admin". Spero di avere un senso.

risposta

16

perché non controllate se c'è un returnUrl prima dei reindirizzamenti personalizzati?

[HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) 
    { 
     if (ModelState.IsValid) 
     { 
       var user = await UserManager.FindAsync(model.UserName, model.Password); 
       if (user != null) 
       { 
        await SignInAsync(user, model.RememberMe); 
        if (String.IsNullOrEmpty(returnUrl)) 
        { 
         if (UserManager.IsInRole(user.Id, "Employer")) 
         { 
          return RedirectToAction("Index", "Employer"); 
         } 
         //role Admin go to Admin page 
         if (UserManager.IsInRole(user.Id, "Admin")) 
         { 
          return RedirectToAction("Index", "Admin"); 
         } 
        } 
        else 
        { 
         return RedirectToLocal(returnUrl); 
        } 
       } 
       else 
       { 
        ModelState.AddModelError("", "Invalid username or password."); 
       } 
     } 

     // If we got this far, something failed, redisplay form 
     return View(model); 
    } 

In questo modo, se si accede a foo.com/admin, verrà generato 401 e verrà reindirizzato al login. Quindi, se accedi come datore di lavoro, genererà 401 e ti reindirizzerà per accedere nuovamente.

Dai commenti: "Posso semplicemente eseguire il reindirizzamento (returnUrl) ed eliminare il metodo di azione RedirectToLocal?"

RedirectToLocal(returnUrl) controlli di metodo se Url.IsLocalUrl(returnUrl). Quindi è necessario per prevenire gli attacchi Open Redirect.

+0

Ciao, puoi spiegare perché l'istruzione else restituisce RedirectToLocal (returnUrl); è necessario? – Mindless

+0

posso semplicemente eseguire il reindirizzamento (returnUrl) ed eliminare il metodo di azione RedirectToLocal? – Mindless

+0

è necessario causa di controllo se (Url.IsLocalUrl (returnUrl)) – tmg

1

Nonostante l'articolo [this] scritto nel 2008, mi ha aiutato con la soluzione a questo problema. Fornisce tutti gli esempi di codice necessari per reindirizzare gli utenti all'accesso senza ingombrare il metodo di accesso. Se aggiungi un nuovo ruolo e desideri reindirizzare gli utenti con quel ruolo, è semplice come aggiungere una riga in web.config.

Mi sono imbattuto in un gotcha. Nel suo articolo ha il seguente codice quale si possono mettere nel vostro AccountController (o dovunque si desidera eseguire il redirect):

/// <summary> 
/// Redirect the user to a specific URL, as specified in the web.config, depending on their role. 
/// If a user belongs to multiple roles, the first matching role in the web.config is used. 
/// Prioritize the role list by listing higher-level roles at the top. 
/// </summary> 
/// <param name="username">Username to check the roles for</param> 
private void RedirectLogin(string username) 
{ 
    LoginRedirectByRoleSection roleRedirectSection = (LoginRedirectByRoleSection)ConfigurationManager.GetSection("loginRedirectByRole"); 
    foreach (RoleRedirect roleRedirect in roleRedirectSection.RoleRedirects) 
    { 
     if (Roles.IsUserInRole(username, roleRedirect.Role)) 
     { 
      Response.Redirect(roleRedirect.Url); 
     } 
    } 
} 

La mia domanda non riusciva a trovare un provider di ruoli, e quando ho aggiunto uno nel web .config, ho avuto difficoltà a trovare i miei ruoli. Ho deciso di abbandonare il ruolo del provider e utilizzare UserManager per ottenere l'utente e i ruoli:

/// <summary> 
    /// Redirect the user to a specific URL, as specified in the web.config, depending on their role. 
    /// If a user belongs to multiple roles, the first matching role in the web.config is used. 
    /// Prioritize the role list by listing higher-level roles at the top. 
    /// </summary> 
    /// <param name="username">Username to check the roles for</param> 
    private void RedirectLogin(string username) 
    { 
     LoginRedirectByRoleSection roleRedirectSection = (LoginRedirectByRoleSection)ConfigurationManager.GetSection("loginRedirectByRole"); 
     var user = UserManager.FindByName(username); 
     var rolesForUser = UserManager.GetRoles(user.Id); 
     foreach (RoleRedirect roleRedirect in roleRedirectSection.RoleRedirects) 
     { 
      if (rolesForUser.Contains(roleRedirect.Role)) 
      { 
       Response.Redirect(roleRedirect.Url); 
      } 
     } 
    }