Using IUserValidator to provide additional user validation rules in ASP.NET Core Identity

Using an IValidator to apply extra validation rules when creating users

In my recent series of posts I extended the UserManager class from ASP.NET Core Identity (specifically its CreateAsync method) in order to confirm that the user was permitted to register and also to update a property in the User being created from data in the application database. If I hadn't needed to also modify the user I could've taken the simpler route of creating a class that implements IUserValidator. This interface contains a single method, ValidateAsync, which does all the work:

public Task<IdentityResult> ValidateAsync (UserManager<TUser> manager, TUser user);

Implementing this as a custom validator that performs the same work as the code I placed into my custom UserManager looks something like this:

public class MyUserValidator : IUserValidator<ApplicationIdentityUser>
{
    public HumanResourcesDatabaseContext DatabaseContext { get; set; }

    public MyUserValidator(HumanResourcesDatabaseContext databaseContext)
    {
        DatabaseContext = databaseContext;
    }

    public Task<IdentityResult> ValidateAsync(UserManager<ApplicationIdentityUser> manager, ApplicationIdentityUser user)
    {
        var matchingUser = DatabaseContext.Employees.FirstOrDefault(candidateUser => candidateUser.EmailAddress.Equals(user.Email, StringComparison.OrdinalIgnoreCase));

        if (matchingUser == null)
        {
            return Task.FromResult(IdentityResult.Failed(new IdentityError { Description = "Sorry, your email address isn't recognised as an employee by ValidateAsync" }));
        }
        else
        {
            return Task.FromResult(IdentityResult.Success);
        }
    }
}

The ASP.NET Core runtime will take care of injecting the database context that it depends on, once its been wired into Identity in the ConfigureServices method:

services.AddDefaultIdentity<ApplicationIdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddUserValidator<MyUserValidator>();

With that done, hitting F5 in Visual Studio to go to the web application and attempting to register with an email address that isn't present in the database gives the expected result, registration is rejected by the validator:

Registration of a new user rejected by the custom IUserValidator that's been hooked into the registration process

That's all there is to it, really! It's definitely a lighter-touch way of implementing a way of checking whether a new user meets additional criteria or not. In my use-case I could even "hijack" the validator to add the extra values I want to persist to the user being created, but there's something that leaves me quite uneasy having something that's supposed to validate have a side-effect.

About Rob

I've been interested in computing since the day my Dad purchased his first business PC (an Amstrad PC 1640 for anyone interested) which introduced me to MS-DOS batch programming and BASIC.

My skillset has matured somewhat since then, which you'll probably see from the posts here. You can read a bit more about me on the about page of the site, or check out some of the other posts on my areas of interest.

No Comments

Add a Comment