Login with either email or username and ignore upper/lower cases for UserName during login

asp.net-identity asp.net-mvc asp.net-mvc-5 authentication entity-framework-6

Question

I'm wokring in a Asp.Net MVC5 web app with EntityFramework 6. I added the UserName attribute to the AspNetUser db table, more exactly I made the UserName to be user chosen, not to be the email.

But in this tutorial ASP.NET Identity 2.0.0 – UserName and Email separation it says: "although login page requires an email address to log in it actually uses model.UserName to validate provided email.". So why does it require the UserName even while it says it's using the Email property, where is that rule being setup and where/how can I change it?

And more important: How can I make the login to work with either email or username like in facebook and also to ignore upper/lowercases during login?

Edited; the code changes I made:

I added this property in the RegisterViewModel

[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }

Added this code in the Register view:

<!-- (...) -->
<div class="form-group">
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
    @Html.TextBoxFor(m => m.UserName, new { @class = "form-control " })
</div>
</div>
<!-- (...) -->

Changed the Register action method to use the also UserName when creating a new user:

// (...)
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
// (...)

Replaced the Email attribute in the LoginViewModel with:

[Required]
[Display(Name = "User Name")]
public string UserName { get; set; }

And also in the login view I replaced the Email with UserName:

<!-- (...) -->
            <div class="form-group">
                @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
                <div class="col-md-10">
                    @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
                    @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
                </div>
            </div>
            <!-- (...) -->

And also changed the Login action method to use the UserName instead of the Email to login:

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
    return View(model);
}

// This doesn't count login failures towards lockout only two factor authentication
// To enable password failures to trigger lockout, change to shouldLockout: true
var result = await SignInHelper.PasswordSignIn(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
// (...)
1
2
7/31/2016 6:22:39 PM

Accepted Answer

If you are comfortable with making and additional call to the database in the case of it being an email address, here is an example of what you can try.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) {
    if (ModelState.IsValid) {
        string username = model.UserName;
        ApplicationUser user = null;
        // CHECK FOR EMAIL
        if(IsValidEmail(username)) {
            user = await userManager.FindByEmailAsync(username);
            if(user != null) username = user.UserName;
            else {
                // If user with email address does not exists, here is a good place
                // to exit as we have already ascertained that the user is not in the system
                ModelState.AddModelError("", "Invalid user name or password provided.") 
                return View(model); 
            }                
        }
        // END CHECK FOR EMAIL
        user = await userManager.FindAsync(username, model.Password);
        if (user != null) {
            var result = await SignInHelper.PasswordSignIn(username, model.Password, model.RememberMe, shouldLockout: false);
            switch (result) {
                //...code removed for brevity
            }
        } else {
            ModelState.AddModelError("", "Invalid user name or password provided.") 
        }

    }

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

private static bool IsValidEmail(string email) {
    string MatchEmailPattern =
       @"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@" +
       @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\." +
       @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|" +
       @"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$";

    if (!string.IsNullOrWhiteSpace(email)) {
        string pattern = MatchEmailPattern;
        return System.Text.RegularExpressions.Regex.IsMatch(email, pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    } else {
        return false;
    }
}
2
7/31/2016 8:03:01 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow