Adding custom Claims to a .net Core 3.1 Project

Published on Wednesday, 15 April 2020

Like many people, when running my .net Core 3.1 Applciation, I need to keep track of some custom properties when a user is logged in. Previously, I may have put this into a custom Session Object, but moving to Azure and .net Core, wanting to utilise the scaling up ability, whilst penny pinching (not running a Redis Server etc), this wasn't an option.

Turns out, this is simplier than it seems.

To achieve this, we need:

A custom ApplicationDBContext:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }
}

Which has a custom Application User:

public class ApplicationUser : IdentityUser<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

A custom Application Role:

public class ApplicationRole : IdentityRole<int>
{
}

A factory to specify the claims:

public class MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
{
    public MyUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager, IOptions<IdentityOptions> optionsAccessor)
        : base(userManager, roleManager, optionsAccessor)
    {
    }

    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        var identity = await base.GenerateClaimsAsync(user);
        identity.AddClaim(new Claim("FirstName", user.FirstName ?? ""));
        identity.AddClaim(new Claim("LastName", user.LastName ?? ""));
        return identity;
    }
}

Then in our Startup.cs, we need to use DI to inject the following:

services
    .AddIdentity<ApplicationUser, ApplicationRole>()
    .AddRoleManager<RoleManager<ApplicationRole>>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders()
    .AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>();

Then, anywhere we use User, we are able to:

var FirstName = User.FindFirst("FirstName").Value;