I’ve been testing out the new version of ASP.NET Identity and had the need to include additional claims in the ClaimIdentity
generated when a user is authenticated.
Transforming Claims Identity
ASP.NET Core supports Claims Transformation out of the box. Just create a class that implements IClaimsTransformer
:
public class ClaimsTransformer : IClaimsTransformer
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
((ClaimsIdentity)principal.Identity).AddClaim(new Claim("ProjectReader", "true"));
return Task.FromResult(principal);
}
}
To register the claims transformer, add the following inside your Configure
method in Startup.cs
:
app.UseClaimsTransformation(new ClaimsTransformationOptions
{
Transformer = new ClaimsTransformer()
});
One problem with the current implementation of the claims transformation middleware is that claims transformer instances have to be created during configuration. This means no DI making it difficult to handle loading claim information from a database.
Note: I’m told this will be fixed in RC2.
Claims Identity Creation
In my application I’d extended the default ApplicationUser
class with additional properties for first and last name. I wanted these properties to be included in the generated ClaimsIdentity
:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
ASP.NET Core Identity has a SignInManager<TUser>
responsible for signing users into your application. Internally it uses a IUserClaimsPrincipalFactory<TUser>
to generate a ClaimsPrincipal
from your user.
The default implementation only includes username and user identifier claims. To add additional claims we can create our own implementation of IUserClaimsPrincipalFactory<TUser>
or derive from the default UserClaimsPrincipalFactory
:
public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public AppClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
((ClaimsIdentity)principal.Identity).AddClaims(new[] {
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
});
return principal;
}
}
To register the custom factory we add the following to the ConfigureServices
method in startup.cs
after the services.AddIdentity()
call:
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();