2014-09-24 3 views
5

Mi chiedo se ci sia un percorso più efficiente da portare qui. Utilizzo di AspNet.Identity Desidero consentire all'utente di accedere alla stessa casella di testo utilizzando il proprio UserName o Email. Sono andato avanti e ho affrontato questo problema nel AccountController Login ActionResult. Corro il controllo prima di chiamare:Permetti all'utente di accedere con Email o UserName (AspNet.Identity)

var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true); 

Il Check:

//TODO: determine if there is a more efficient way to allow user to login either with Email || UserName 
if (model.UserName.Contains("@")) 
{ 
    using (var context = new ApplicationDbContext()) 
    { 
     model.UserName = (context.Users.Any(p => p.Email == model.UserName)) ? 
      context.Users.SingleOrDefault(p => p.Email == model.UserName).UserName : 
      model.UserName; 
    } 
} 

Le mie preoccupazioni sono qui due volte:

  1. il loro è un modo pratico più efficace per farlo.
  2. Sto introducendo nuovi rischi per la sicurezza o rischi di prestazioni in questo modo?

sto compreso l'intero ActionResult sotto per riferimento.

// 
// POST: /Account/Login 
[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 

    //TODO: determine if there is a more efficient way to allow user to login either with Email || UserName 
    if (model.UserName.Contains("@")) 
    { 
     using (var context = new ApplicationDbContext()) 
     { 
      model.UserName = (context.Users.Any(p => p.Email == model.UserName)) ? 
       context.Users.SingleOrDefault(p => p.Email == model.UserName).UserName : 
       model.UserName; 
     } 
    } 

    // This doesn't count login failures towards account lockout 
    // To enable password failures to trigger account lockout, change to shouldLockout: true 
    var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true); 
    switch (result) 
    { 
     case SignInStatus.Success: 
      return RedirectToLocal(returnUrl); 
     case SignInStatus.LockedOut: 
      return View("Lockout"); 
     case SignInStatus.RequiresVerification: 
      return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe }); 
     case SignInStatus.Failure: 
     default: 
      ModelState.AddModelError("", "Invalid login attempt."); 
      return View(model); 
    } 
} 

legati problema github #2 e #4

+2

È possibile avviare da non controllare se la voce ha un '@'. –

+0

@RedSerpent il motivo per cui sto verificando se la voce ha un '@' è perché non voglio colpire il database con una query LINQ 'context.Users.Any' se non ne ho bisogno. Colpire il database sarebbe una soluzione migliore? Che problemi hai con il controllo di '@'? – aaronmallen

+0

Ho avuto lo stesso problema quando avvio con Identity 1.0, ho dovuto inserire i campi email e userName come stessi. – DSR

risposta

8

Ci sarà un problema di sicurezza. È possibile ottenere il nome utente di un altro utente, se si conosce la sua e-mail:

  1. scrivere la sua e-mail e la password sbagliata
  2. allora il sistema carica il nome utente corrispondente, esegue la convalida della password che non riesce e restituisce il modello con nome utente sovrascritto

Vorrei dichiarare una nuova variabile invece del modello.UserName riutilizzo. E la query sarà un po 'più efficace se si utilizza FirstOrDefault:

var userName = model.UserName; 
    using (var context = new ApplicationDbContext()) 
    { 
     var user = context.Users.FirstOrDefault(p => p.Email == model.UserName); 
     if (user != null) 
     { 
      userName = user.UserName; 
     } 
    } 

var result = await SignInManager.PasswordSignInAsync(userName, model.Password, model.RememberMe, shouldLockout: true); 
+0

Tutti i punti validi e introdurrò certamente alcuni di questi cambiamenti. Tuttavia, si sta ancora utilizzando lo stesso metodo che sto già usando, non c'è un modo in cui questo è comunemente realizzato con AspNet.Identity? – aaronmallen

+1

@aaronmallen non lo so, ma penso che la tua soluzione sia abbastanza buona. –