I'm having some difficulty trying to understand this, and I can't find a more specific solution for my problem. The problem is the following, I have an API with many endpoints, all of them use Authorize and a token generated with Jwt. What I'm trying to do, and I'm not sure if it's possible, is that a controller uses an exclusive token for it. That is to say, that this token if the user has access to it does not allow him to use it in the other existing endpoints. I would also like that it is not necessary to modify the rest of the [Authorize] headers because there are a lot of endpoints.
Is it possible? Could you if it is not too much trouble point me a little better how I should take this inconvenient?
Thank you!
I share with you some actual code:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme => JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
RequireExpirationTime = false,
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = "FULLAPI",
ValidIssuer = "FULLAPI",
IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey))
};
});
Tried using policies and schemes but didn't get to work how I wanted.
CodePudding user response:
you can define multiple authentication schemes.
.AddJwtBearer("Scheme1", options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
RequireExpirationTime = false,
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = "FULLAPI",
ValidIssuer = "FULLAPI",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey))
};
})
.AddJwtBearer("Scheme2", options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
RequireExpirationTime = false,
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = "FULLAPI",
ValidIssuer = "FULLAPI",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey2))
};
});
and use like this.
[Authorize(AuthenticationSchemes = "Scheme1")]
public IActionResult Get()
{
CodePudding user response:
This is a much cleaner way without modifying the existing [Authorize]
attribute.
First, modify the AddJwtBearer
as below -
.AddJwtBearer(options =>
{
options.Events.OnTokenValidated = context =>
{
var controller = context.HttpContext.Request.RouteValues["controller"];
var action = context.HttpContext.Request.RouteValues["action"];
// validation logic goes here
return Task.CompletedTask;
};
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
RequireExpirationTime = false,
ValidateIssuer = false,
ValidateAudience = false,
ValidAudience = "FULLAPI",
ValidIssuer = "FULLAPI",
IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecurityKey))
};
});
One of the ways would be that you group the all endpoints and map with a key having a specific group of endpoints. Then you can put that key in claims when you are creating the token.
Now that you have access to the controller
and action
names and the token context, You can directly check the claims and validate if the key is valid for the currently requested endpoint and send the unauthorize response if the token does not meet the requirement.