Implementing custom claim with extended MVC Core Identity user

davewilliams459 picture davewilliams459 · Feb 6, 2018 · Viewed 10.4k times · Source

How can I create a custom authorize claim in MVC Core 2.0 (using AspNetCore.identity) to verify a custom user boolean property? I have extended the IdentityUser (ApplicationUser) to include a boolean value "IsDeveloper". I am using claims based authentication and would like to add a custom claim, but am not certain where to start. How can I create a custom claim that will:

  1. Find the current (customized) Core.Identity user.
  2. Evaluate the a custom identity user bool value?

I understand the core identity claims MSDN: Claims Based Authentication, but am new to custom claims, so I am not sure where to begin. The Online documents that I have found do not work or does not fit my scenario.

Answer

AlbertK picture AlbertK · Feb 7, 2018

So, you need to create custom claims somewhere and then check it through a custom policy or manually.

1) Custom claims adding

JwtBearer authentication

You can do something like this:

In your controller action that returns jwt-token you can add your custom claim:

[HttpGet]
public dynamic GetToken(string login, string password)
{
    var handler = new JwtSecurityTokenHandler();

    var sec = "12312313212312313213213123123132123123132132132131231313212313232131231231313212313213132123131321313213213131231231213213131311";
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(sec));
    var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);

    var user = GetUserFromDb(login);
    var identity = new ClaimsIdentity(new GenericIdentity(user.Email), new[] { new Claim("user_id", user.Id) });
    if (user.IsDeveloper)
        identity.AddClaim(new Claim("IsDeveloper", "true"));
    var token = handler.CreateJwtSecurityToken(subject: identity,
                                                signingCredentials: signingCredentials,
                                                audience: "ExampleAudience",
                                                issuer: "ExampleIssuer",
                                                expires: DateTime.UtcNow.AddSeconds(100));
    return handler.WriteToken(token);
}

ASP.NET Core Identity authentication

You need to implement a custom IUserClaimsPrincipalFactory or use UserClaimsPrincipalFactory as a base class:

public class ApplicationClaimsIdentityFactory: Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory <ApplicationUser>
{
    UserManager<ApplicationUser> _userManager;
    public ApplicationClaimsIdentityFactory(UserManager<ApplicationUser> userManager, 
        IOptions<IdentityOptions> optionsAccessor):base(userManager, optionsAccessor)
    {}
    public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
    {
        var principal = await base.CreateAsync(user);
        if (user.IsDeveloper)
        {
            ((ClaimsIdentity)principal.Identity).AddClaims(new[] {
                new Claim("IsDeveloper", "true")
            });
        }
        return principal;
    }
}

then you need to register it in Startup.ConfigureServices:

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, ApplicationClaimsIdentityFactory>();

2) Check the claim

Custom policy

In Startup.ConfigureServices:

services.AddAuthorization(options =>
{
    options.AddPolicy("Developer", policy =>
                        policy.RequireClaim("IsDeveloper", "true"));
});

and protect your action for developers:

[Authorize(Policy = "Developer"), HttpGet]
public string DeveloperSecret()
{
    return "Hello Developer"
}

Check the claim manually

Somewhere in the controller:

bool isDeveloper = User.Claims.Any(c => c.Type == "IsDeveloper" && c.Value == "true")

If you are using some other authentication the idea should be the same.