ASP.NET Core - Add role claim to User

Arnaud F. picture Arnaud F. · Aug 25, 2017 · Viewed 17.2k times · Source

I've an ASP.NET Core (based on .NET Framework) using Windows Authentication. Point is, I need to add a role claim on that user and this role is stored in a distant database.

I've read so much thing about OWIN/Cookie/UserManager/UserStore/Identity and so on that I'm lost.

Question : How do I add a role claim for current user logged in (windows) for the whole application in the easiest way?

What I need is to easily use [Authorize(Role= "MyAddedRole")] or bool res = User.IsInRole("MyAddedRole")

Thanks

Answer

Arnaud F. picture Arnaud F. · Aug 26, 2017

Answering myself, so what I did :

Create my own UserClaimStore (I only need this store, not the others):

public class MyIdentityStore :
    IUserClaimStore<IdentityUser>
{
    private MyDbContext _myDbContext;
    private bool _disposed = false; 

    public MyIdentityStore(MyDbContext myDbContext)
    {
        _myDbContext = myDbContext;
    }

    #region IUserClaimStore
    public Task<IList<Claim>> GetClaimsAsync(IdentityUser user, CancellationToken cancellationToken)
    {
        // logic here to retrieve claims from my own database using _myDbContext
    }

    // All other methods from interface throwing System.NotSupportedException.
    #endregion

    #region IDisposable Support

    protected virtual void Dispose(bool disposing)
    { /* do cleanup */ }
    #endregion
}

Then created my own ClaimTransformer :

public class MyClaimsTransformer : IClaimsTransformer
{
    private UserManager<IdentityUser> _userManager;

    public MyClaimsTransformer(UserManager<IdentityUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        var identity = ((ClaimsIdentity)context.Principal.Identity);

        // Accessing the UserClaimStore described above
        var claims = await _userManager.GetClaimsAsync(new IdentityUser(identity.Name));
        identity.AddClaims(claims);

        return await Task.FromResult(context.Principal);
    }
}

Endly, in Startup.cs :

    public void ConfigureServices(IServiceCollection services)
    {
        /* All other stuff here */ 

        // Adding Database connection
        services.AddDbContext<MyDbContext>(o => /* my options */);

        // Associates our database and store to identity
        services.AddIdentity<IdentityUser, IdentityRole>()
            .AddEntityFrameworkStores<MyDbContext>()
            .AddUserStore<MyIdentityStore>();

        // Claims transformation from database to claims
        services.AddTransient<IClaimsTransformer, MyClaimsTransformer>();
    }


    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        /* All other stuff here */ 

        app.UseIdentity();

        app.UseClaimsTransformation(async (context) =>
        { // Retrieve user claims from database
            IClaimsTransformer transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
            return await transformer.TransformAsync(context);
        });
    }

And now I can freely use [Authorize(Roles = "MyRole")] or User.IsInRole("MyRole") or even User.HasClaim(/* */) !