ASP.NET Core - Add role claim to User

2020-05-18 17:35发布

问题:

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

回答1:

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



回答2:

Well beside the answers, I just found the answer which is totally predefined in asp .net core. When you are adding claims just :

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, UserName),
    new Claim(ClaimTypes.Role, "User"),
    new Claim(ClaimTypes.Role, "Admin"),
    new Claim(ClaimTypes.Role, Watever)
};

after that you can just use it as said:

[Authorize(Roles = "Watever")]

or

User.IsInRole("Watever")


回答3:

A User object you're talking about has multiple Identities, which all can have multiple Claims.

One way to add custom claims to the User object is to edit the Identity that is automatically created by your authentication/authorization framework of choice (e.g. OAuth) and that step is specific to each framework, obviously. It boils down to read the docs for that framework to figure out at which point an Identity is being created and extened that point with your custom code adding new claims.

Another, maybe simpler, way is to create a new Identity object (which holds all your additional Claims) and add it to the User list of identities, using AddIdentity() method.

When you access User.Claims that enumeration will return all the claims from all the identities you have on the User object.

So, wherever you're in your application code (the most suitable point would be a sort of a middleware, I suppose) you can do something like this:

var myIdentity = new ClaimsIdentity(new []
{
    new Claim("claim type", "claim value"), 
    new Claim("claim type", "claim value"), 
    new Claim("claim type", "claim value"), 
});

context.User.AddIdentity(myIdentity);

From that point on, each call to User.Claims will return all the original claims on the User object plus your additional claims.