Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding role claims - should i use the IClaimsTransformer

We would like to add a lot of role claims to the current principal (we use the Authorize(Roles) attribute), and found the IClaimsTransformer that looks like a perfect fit.

We've registerd it like this

 app.UseClaimsTransformation(new ClaimsTransformationOptions
        {
            Transformer = new GetRolesFromDatabaseClaimsTransformer(new RoleManager2(Configuration.GetConnectionString("ourcoolapp")))
        });

And the transform is like this:

public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
        // A hacky way to not load on all requests. Better ideas?
        if (!context.Context.Request.Path.Value.Contains("api/"))
        {
            return Task.FromResult(context.Principal);
        }

        var roleClaims = RoleManager.GetRolesForUser(context.Principal.Identity.Name).Select(roleName => new Claim("role", roleName));

        var claims = new List<Claim> { };
        var identity = context.Principal.Identity as ClaimsIdentity;
        claims.AddRange(identity.Claims);
        claims.AddRange(roleClaims);

        var userIdentity = new ClaimsIdentity(claims, "local");
        var userPrinicpal = new ClaimsPrincipal(userIdentity);

        return Task.FromResult(userPrinicpal);
}

Question: Are there alternative, or smarter ways of adding the role claims?

Thanks

Larsi

like image 724
Larsi Avatar asked Oct 29 '22 11:10

Larsi


1 Answers

Another option could be UserClaimsPrincipalFactory

It provides methods to create claims principal for a given user and you can customize it just like ClaimsTransformer.

By default It adds UserName and UserId to claim collection. In order to customize it you can driver from UserClaimsPrincipalFactory and override CreateAsync

public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<User, Role>
{
    public AppClaimsPrincipalFactory(UserManager<User> userManager,
        RoleManager<Role> roleManager,
        IOptions<IdentityOptions> optionsAccessor, 
        ILogger<AppClaimsPrincipalFactory> logger) 
        : base(userManager, roleManager, optionsAccessor)
    {
        logger.LogInformation("AppClaimsPrincipalFactory ctor");
    }

    public override async Task<ClaimsPrincipal> CreateAsync(User user)
    {
        var principal = await base.CreateAsync(user);
        ((ClaimsIdentity)principal.Identity).AddClaims(new []
        {
            new Claim("Foo", "Bar"), 
        });

        return principal;
    }
}

And Register the Factory in DI:

services.AddScoped<IUserClaimsPrincipalFactory<User>,  AppClaimsPrincipalFactory>();  

It will change/override the claim whenever the user's claims requested.
For more info take a look at source at GitHub.

like image 193
Soren Avatar answered Nov 11 '22 09:11

Soren