IdentityServer4 Role Based Authorization for Web API with ASP.NET Core Identity
The problem is that the claims are not added to the access token.
There are two tokens, the access token and the identity token.
When you want to add claims to the identity token, then you'll have to configure the IdentityResource. If you want to add claims to the access token, then you'll have to configure the ApiResource (or scope).
This should fix it for you:
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API"),
new ApiResource("roles", "My Roles", new[] { "role" })
};
}
Make sure the client (postman) requests the roles
scope.
I did test it with the sample code from IdentityServer. In my setup I've added the role 'TestUser' to alice:
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password",
Claims = new List<Claim> { new Claim("role", "TestUser") }
},
The Postman call, please note the requested scope:
The access token including the role claim:
I have solved this by adding 'role' in Type column in ApiClaims table see the image below.
ApiResourceId column name found in ApiClaims table is primary key of ApiResources table with Id column name.
In your Api, somewhere before services.AddAuthentication("Bearer")
add a line for JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
.
More info at this post.
EDIT:
Additionally, try to update your identity resources configuration with roles
identity resource.
// scopes define the resources in your system
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource("roles", new[] { "role" })
};
}
And your client AllowedScopes
needs adding roles
as well then:
AllowedScopes = { "api1", "roles" }
Lastly, your postman request should then ask for the roles
scope to be included scope: api1 roles
.
EDIT 2: Also, update your profile to include roles in the issued claims:
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
context.IssuedClaims.AddRange(context.Subject.Claims);
var user = await _userManager.GetUserAsync(context.Subject);
var roles = await _userManager.GetRolesAsync(user);
foreach (var role in roles)
{
context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, role));
}
}
The above should probably be updated to only add roles
claim when it is requested.
Make sure your newly issued JWT tokens now include roles
claim like the one in below:
eyJhbGciOiJSUzI1NiIsImtpZCI6ImU0ZjczZDU5MjQ2YjVjMmFjOWVkNDI2ZGU4YzlhNGM2IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NDY0Mzk0MTIsImV4cCI6MTU0NjQ0MzAxMiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC9yZXNvdXJjZXMiLCJhcGkxIiwicm9sZXMiXSwiY2xpZW50X2lkIjoicm8uY2xpZW50Iiwic3ViIjoiMiIsImF1dGhfdGltZSI6MTU0NjQzOTQxMSwiaWRwIjoibG9jYWwiLCJyb2xlIjpbIkFkbWluIiwiU3R1ZGVudCJdLCJzY29wZSI6WyJvcGVuaWQiLCJhcGkxIiwicm9sZXMiXSwiYW1yIjpbInB3ZCJdfQ.irLmhkyCTQB77hm3XczL4krGMUqAH8izllG7FmQhZIQaYRqI7smLIfrqd6UBDFWTDpD9q0Xx0oefUzjBrwq2XnhGSm83vxlZXaKfb0RdLbYKtC4BlypgTEj8OC-G0ktPqoN1C0lh2_Y2PfKyQYieSRlEXkOHeK6VWfpYKURx6bl33EVDcwe_bxPO1K4axdudtORpZ_4OOkx9b_HvreYaCkuUqzUzrNhYUMl028fPFwjRjMmZTmlDJDPu3Wz-jTaSZ9CHxELG5qIzmpbujCVknh3I0QxRU8bSti2bk7Q139zaiPP2vT5RWAqwnhIeuY9xZb_PnUsjBaxyRVQZ0vTPjQ