We have standard .NET Core [Authorize(Roles = "Foo")]
authorization attributes.
They are set up in Startup.cs
to check roles via a JWT in the Authorize header in the standard, out-of-the-box way, e.g.:
.AddJwtBearer(jwtBearerOptions => {...}
Our current tokens look like below and work perfectly:
{
"role": "Foo",
"exp": 1937249412,
}
Our new tokens will look like the tokens below. We have NO control over the incoming tokens (but do have the symmetric key):
{
"www.bar.com/role": "Foo",
"exp": 1937249412,
}
Core question: Is there any way to change [Authorize]
to look for the token in www.bar.com/role
and not Role
in the JWT body, which it does by default?
P.S. I know I can add middleware to write a Role
to the token and re-sign the token. I also know that I can write [CustomAuthorize]
attributes or use policy-based authentication. It just feels like there should be an easy way to do something this simple without having to mess with incoming requests OR replacing the [Authorize]
attribute in the whole app.
First solution that comes to mind
You could play it via policies and use roles in the background. Here is an example. In your controller:
[Authorize(Policy = "Foo")]
public Whatever() {}
And then you register your policy like this:
services.AddAuthorization(options =>
{
options.AddPolicy("Foo", policy => policy.RequireClaim("www.bar.com/role", new[] { "Foo" }));
}
I.e. your "Foo" policy requires a user to have the value "Foo" for the claim "www.bar.com/role".
Digging deeper into the source
In fact if you add the Authorize
attribute with a role, not much more happens in the background as in the Policy example above. .net creates an authorization policy with a RolesAuthorizationRequirement
, and this requirement checks the roles by calling context.User.IsInRole
, which, in turn calls HasClaim(_identities[i].RoleClaimType, role)
on the ClaimsIdentity
. RoleClaimType
is set in .net ClaimsIdentity
to "roles/" by default.
So another way would probably be intercepting the creation of the ClaimsIdentity and calling it with another constructor which has a "roleType" parameter, which allows overriding of the default role claim name.
A probably better solution
So I've looked for the ClaimsIdentity and found this docu. It seems that you can get to it via token validation parameters:
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "www.bar.com/role"
}
})