Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow user to log in with either Email OR UserName (AspNet.Identity)

I am wondering if there is a more efficient route to take here. Using AspNet.Identity I would like to allow the user to sign in to the same text box using either their UserName or Email. I went ahead and addressed this issue in the AccountController Login ActionResult. I run the check before calling:

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

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

My concerns here are two fold:

  1. Is their a more efficient practical way to do this.
  2. Am I introducing any new security risks or performance risks by doing it this way?

I am including the entire ActionResult below for reference.

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

related github issue #2 and #4

like image 219
aaronmallen Avatar asked Sep 24 '14 05:09

aaronmallen


People also ask

What is Aspnet core identity used for?

ASP.NET Core Identity: Is an API that supports user interface (UI) login functionality. Manages users, passwords, profile data, roles, claims, tokens, email confirmation, and more.

How can check user already login in asp net?

You need to set FormsAuthentication. SetAuthCookie(PrimaryKey, false); when user is loggedIn. Here, PrimaryKey is the key that you can use throughout the session for identification of the user using User.Identity.Name . Also, when user log out of the application, you will call FormsAuthentication.

Is ASP NET identity support third party authentication?

The Identity framework is another dependency that we will add to our application in the project. js file. This framework allows us to add features where users can register and log in with a local password. The framework also supports two-factor authentication, third-party identity providers and other features.


1 Answers

There will be one security issue. You can get the username of another user if you know his email:

  1. write his email and wrong password
  2. then the system loads the corresponding user name, performs password validation which fails and returns the model with overwritten username

I would declare new variable instead of model.UserName reuse. And your query will be a little more effective if you use 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);
like image 169
Marian Ban Avatar answered Sep 21 '22 05:09

Marian Ban