Email Addresses as User Names in ASP.NET Identity

It’s common for web applications to use email addresses instead of user names to distinguish users. However, if you are using ASP.NET Identity, you have probably noticed that it has UserName built into the IUser interface. Since Identity assumes that this is the distinguishing field for the user, it’s not crazy to think that it might be a good place to drop the email address. In order to have Identity allow an email address in this field, you will need to write a custom IIdentityValidator.

/// <summary>
/// A replacement for the <see cref="UserValidator"/> which requires that an email 
/// address be used for the <see cref="IUser.UserName"/> field.
/// </summary>
/// <typeparam name="TUser">Must be a type derived from <see cref="Microsoft.AspNet.Identity.IUser"/>.</typeparam>
/// <remarks>
/// This validator check the <see cref="IUser.UserName"/> property against the simple email regex provided at
/// http://www.regular-expressions.info/email.html. If a <see cref="UserManager"/> is provided in the constructor,
/// it will also ensure that the email address is not already being used by another account in the manager.
/// 
/// To use this validator, just set <see cref="UserManager.UserValidator"/> to a new instance of this class.
/// </remarks>
public class CustomUserValidator<TUser> : IIdentityValidator<TUser>
    where TUser : class, Microsoft.AspNet.Identity.IUser
{
    private static readonly Regex EmailRegex = new Regex(@"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    private readonly UserManager<TUser> _manager;

    public CustomUserValidator()
    {
    }

    public CustomUserValidator(UserManager<TUser> manager)
    {
        _manager = manager;
    }

    public async Task<IdentityResult> ValidateAsync(TUser item)
    {
        var errors = new List<string>();
        if (!EmailRegex.IsMatch(item.UserName))
            errors.Add("Enter a valid email address.");

        if (_manager != null)
        {
            var otherAccount = await _manager.FindByNameAsync(item.UserName);
            if (otherAccount != null && otherAccount.Id != item.Id)
                errors.Add("Select a different email address. An account has already been created with this email address.");
        }

        return errors.Any()
            ? IdentityResult.Failed(errors.ToArray())
            : IdentityResult.Success;
    }
}

UPDATE 03/28/2014: As John Holliday points out, Identity 2.0 requires that the TUser be a reference type, so where TUser : Microsoft.AspNet.Identity.IUser was updated to where TUser : class, Microsoft.AspNet.Identity.IUser. Thanks John!

This validator ensures that the UserName field is set to an email address. It also optionally ensures that the email address is not being used by another account.

UPDATE 11/17/2013: I just found out that ValidateAsync is called at times other than when creating a new user, such as when adding external logins with UserManager.AddLoginAsync. This caused errors to occur with the original code because it thought it found duplicates. The fix this, && otherAccount.Id != item.Id has been added when checking for duplicates.

In order to use this validator, just set your UserManager.UserValidator to a new instance of it.

[Authorize]
public class AccountController : Controller
{
    public AccountController()
        : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
    {
        UserManager.UserValidator = new CustomUserValidator<ApplicationUser>(UserManager);
    }

Email Address in MVC 5 Google Authentication

I’m not proud to admit that I spent hours trying to figure out this very simple problem. The goal was simple: when a user logs into my web application using Google authentication, I want to be able to grab their email address so I can store it as part of their user profile. As expected, this is very simple.

I’m assuming you’ve already enabled Google authentication by uncommenting app.UseGoogleAuthentication() in your Startup.Auth.cs.

To get the email address, just hop on over to AccountController.ExternalLoginCallback. Here, after the user has successfully authenticated with Google, you can grab the external identity. That external identity has some default claims in it, one of which (for Google Authentication at least) is the user’s email address.

    //
    // GET: /Account/ExternalLoginCallback
    [AllowAnonymous]
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            return RedirectToAction("Login");
        }

        var externalIdentity = await AuthenticationManager
            .GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);

        var emailClaim = externalIdentity.Claims.FirstOrDefault(x => 
            x.Type.Equals(
                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", 
                StringComparison.OrdinalIgnoreCase));

        var emailAddress = emailClaim != null 
            ? emailClaim.Value 
            : null;

        // Remainder of method excluded for brevity...

The email address claim is identified by the http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress type. If you find that claim, it’s Value is the user’s email address.

If you find that you need other information that is not provided in the external identity by default, John Palmer has some great examples for adding claims on the IdentityUserPropertiesSample GitHub project.

Partial Views with Unobtrusive AJAX

In my recent exploration of web development in ASP.NET, I found what I assume to be a fairly common need to have part of a view/page update without the entire page updating. In my particular case, I wanted to have a page that listed items but also provided a form that allowed you to add an item. When an item was added, the list of items would be updated without having to regenerate the entire page. Continue reading Partial Views with Unobtrusive AJAX