Authorization Role/Policy Attributes Not Working In .Net Core 3
Asked Answered
C

2

7

I've had no luck getting any Role or Policy attributes working in .Net Core 3. I started my project with the .Net Core Angular starter project with authentication. I figured this was something to do with the new .AddDefault methods so I have simplified it as much as I possibly can and it still doesn't work.

Here is my policy:

services.AddAuthorization(options =>
{
    options.AddPolicy("IsAdmin", policy =>
        policy.RequireClaim("role", "admin"));
});

Here is my controller:

[Authorize(Policy = "IsAdmin")]
[Route("api/[controller]")]
public class AdminController : Controller 
{
    ...

I made a custom Profile service that adds the claim to the token,

var claims = new List<Claim>();

if (await _userManager.IsInRoleAsync(user, "Admin"))
{
    claims.Add(new Claim(JwtClaimTypes.Role, "admin"));
}

context.IssuedClaims.AddRange(claims);

Inside my access token (from jwt.io):

enter image description here

Other parts of configure services:

services.AddDefaultIdentity<ApplicationUser>()
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

...

services.AddAuthentication()
    .AddIdentityServerJwt();

The plain [Authorize] tag is working fine with the access token on other controllers.

When I hit this controller with the access token I get a 403 response

What am I missing that is preventing this from working?

Codpiece answered 14/10, 2019 at 8:38 Comment(0)
B
17

I try your code and find that the role claim key has been transformed to the standard Role ClaimsType : http://schemas.microsoft.com/ws/2008/06/identity/claims/role

enter image description here

So using ClaimTypes.Role will fix the problem:

services.AddAuthorization(options => { 
    options.AddPolicy("IsAdmin", policy => 
    { 
        policy.RequireClaim(ClaimTypes.Role,"admin");
    }); 
});

Demo

enter image description here

Beatrix answered 15/10, 2019 at 1:54 Comment(4)
You're right, thanks for your help! Do you have any idea why policy.RequireRole("admin") doesn't work but policy.RequireClaim(ClaimTypes.Role, "admin") does?Codpiece
@Codpiece As far as I know, the http://schemas.microsoft.com/ws/2008/06/identity/claims/role is the standard way in dotnet core. However, although the transformation maps the role for us, it doesn't change the inner _roleClaimType field at the same time, which makes the User.IsInRole() unavailable, thus your policy.RequireRole("admin") doesn't work.Beatrix
@Beatrix Thanks! Is there a way to fix it so RequireRole("admin") would work?Velour
See here: github.com/aspnet/AspNetCore.Docs/issues/14944Codpiece
A
1

You should also be able to achieve this without needing a policy. ASP.NET automatically maps common claims to the Microsoft schema.

When you inspect your access token. You will see you are sending the role claim. But when you look at the claims in the controller, you will notice that it has been transformed to http://schemas.microsoft.com/ws/2008/06/identity/claims/role.

There are two things you can do. Either set the RoleClaimType to ClaimTypes.Role. Like so:

services.Configure<JwtBearerOptions>(IdentityServerJwtConstants.IdentityServerJwtBearerScheme, options => {
    options.TokenValidationParameters.RoleClaimType = ClaimTypes.Role;
});

Or tell the JwtSecurityTokenHandler not to map default inbound claims like this: JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

Since it's a static property this can be done at any time. But I set it somewhere during my service registrations.

Alike answered 9/12, 2022 at 8:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.