Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core - Add role claim to User

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

like image 811
Arnaud F. Avatar asked Aug 25 '17 12:08

Arnaud F.


People also ask

How do I apply a claim in .NET Core?

Adding claims checks Claim based authorization checks are declarative - the developer embeds them within their code, against a controller or an action within a controller, specifying claims which the current user must possess, and optionally the value the claim must hold to access the requested resource.

What is user claims in ASP.NET Core?

Claims can be created from any user or identity data which can be issued using a trusted identity provider or ASP.NET Core identity. A claim is a name value pair that represents what the subject is, not what the subject can do.

What is RoleClaimType?

The RoleClaimType property specifies the claim type of the claim that should be used to provide the value for the role when evaluating this ClaimsIdentity object. The property is set by the constructor. A common value is ClaimTypes.

What is the difference between roles and claims?

Claims are a method of providing information about a user, and roles are a description of a user by way of which roles they belong.


1 Answers

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(/* */) !

like image 113
Arnaud F. Avatar answered Oct 05 '22 07:10

Arnaud F.