How Do I Add New Claims to the ClaimsPrincipal on Login with dotnet Core?

I’ve been playing with stuff for a forthcoming project. One of the requirements will be that different users will see different branding on the site depending on who they are. This information will be stored in the site database, but I was unhappy at the idea of having to pull that data out of the db on every request.

Is there, I wondered, a way to get the information out of the database during a login, and store it as a Claim, in the same way that, by default, the Name claim is stored in the Authentication cookie.

It turned out that this information is remarkably hard to search for. There are a couple of articles based on .NET Core 1.0, but the docs for 2.1 weren’t giving me any joy.

So I made some guesses as to which classes might be involved by looking at the code on github, and looking for other projects that used them.

So I’ve worked out the basic principle, and it involves creating a custom class that implements the interface

IUserClaimsPrincipalFactory<TUser>

where TUser is your app’s User class. Mine is ApplicationUser.

For convenience, to maintain the default behaviours, I inherited by custom class from

UserClaimsPrincipalFactory<TUser,TRole>

Which implements the interface and provides a useful method, GenerateClaimsAsync. I can use that to start building a ClaimsIdentity, then add my own claims.

Here’s my implementation, which, for this demo, merely creates a claim which is the user’s full name. It uses the User which has already been fetched from the database for the login process, so there’s no need for any further database access. If you do need to hit the database, you can simply use Dependency Injection in the class constructor to get a database context or a repository.

public class AppUserClaimsPrincipalFactory<TUser,TRole>
 : UserClaimsPrincipalFactory<TUser,TRole> 
 where TUser: ApplicationUser 
 where TRole : IdentityRole
{
 public AppUserClaimsPrincipalFactory(
 UserManager<TUser> manager, 
 RoleManager<TRole> rolemanager, 
 IOptions<IdentityOptions> options)
   : base(manager, rolemanager, options)
 {
 }

 public async override Task<ClaimsPrincipal> CreateAsync(TUser user)
 {
   var id = await GenerateClaimsAsync(user);
   if (user != null)
   {
     id.AddClaim(new Claim("Zarquon", user.Name));
   }
   return new ClaimsPrincipal(id);
 }
}

Once you’ve got your class implementation, you need to add it to the services for your app in your ConfigureServices, so that the Identity code will pick it up in preference for the default.

I added the following line in ConfigureServices:

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppUserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();

This will cause an instance of my class to be injected into the Identity system when it asks for an instance of the factory, and called when the ClaimsPrincipal is built.

You can basically add any claims you want, and you should probably choose better names than Zarquon.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s