Anthony Chu Contact Me

ASP.NET Identity 2.0 - Logging in with Email or Username

Wednesday, January 22, 2014

With the release of .NET 4.5.1, we got new identity framework – ASP.NET Identity. Version 1.0 of ASP.NET Identity is pretty barebones… missing features such as confirmation of registration and password reset. Thankfully, the team has already released an alpha of ASP.NET Identity 2.0.

There is a lot that is new. Today, I’ll cover how to include the email address field on the registration page, and then allow the user to sign in with either their username or email.

Update ASP.NET Identity to 2.0 Alpha

In NuGet Package Manager, select Include Prerelease and update Microsoft.Asp.Net.Identity.Owin and Microsoft.AspNet.Identity.EntityFramework to 2.0.0-alpha1 (or later).

If we look in Object Browser, IdentityUser in the Entity Framework implementation of ASP.NET Identity now includes an Email field (they also added an IsConfirmed field for registration confirmations).

Add an Email field to the registration page

Because the default project template was created for ASP.NET Identity 1.0, the registration page doesn’t ask for an email address. We’ll have to add this ourselves. First, we add an Email property to the RegisterViewModel

[Required]
[EmailAddress]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }

Next, we add a text box for the email address in the Register view (Register.cshtml)…

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

Finally, we modify the Register action in AccountController.cs to copy the email address to the ApplicationUser object to be saved. We’ll also set IsConfirmed to true for now since we’re not doing anything with this new property yet…

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

Now Email appears as a required field on the registration page…

And the email is saved properly in the database…

Allow users to log in with email or username

Now that all users have an email address, we should allow them to log in by supplying either their username or password. Right now this doesn’t work…

This is because the FindAsync method only searches by username. We’ll need to fix that.

var user = await UserManager.FindAsync(model.UserName, model.Password);

We can easily create an extension method to allow logging in by email as well as username. Add an IdentityExtensions.cs file and paste this in…

using AspnetIdentity20.Models;
using Microsoft.AspNet.Identity;
using System.Threading.Tasks;

namespace AspnetIdentity20
{
    public static class IdentityExtensions
    {
        public static async Task<applicationuser> FindByNameOrEmailAsync
            (this UserManager<applicationuser> userManager, string usernameOrEmail, string password)
        {
            var username = usernameOrEmail;
            if (usernameOrEmail.Contains("@"))
            {
                var userForEmail = await userManager.FindByEmailAsync(usernameOrEmail);
                if (userForEmail != null)
                {
                    username = userForEmail.UserName;
                }
            }
            return await userManager.FindAsync(username, password);
        }
    }
}

The code is pretty straight-forward. We’re checking to see if an email was supplied, and look up the username tied to the email. Now, in the Login action in AccountController.cs, we change the code to call our new extension method.

var user = await UserManager.FindByNameOrEmailAsync(model.UserName, model.Password);

And now we should be able to log in with either our email address or username.