I'm getting 401 unauthorized while using GET with JWT in header. For single role authorized doesn't work as well.
SecurityService.cs - Generated random key on creation. Role is taken from user instance.
private const int TokenExpirationInSeconds = 600;
private readonly IConfiguration _configuration;
public byte[] Key { get; } = RandomNumberGenerator.GetBytes(128);
public string BuildJwtToken(User user)
{
var roles = new List<Role> {user.Role};
var roleClaims = roles.ToDictionary(
q => ClaimTypes.Role,
q => (object) q.Name.ToUpper());
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),
new Claim(JwtRegisteredClaimNames.Aud, _configuration["Jwt:Audience"] ?? string.Empty),
new Claim(JwtRegisteredClaimNames.Iss, _configuration["Jwt:Issuer"] ?? string.Empty),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
Expires = DateTime.UtcNow.AddSeconds(TokenExpirationInSeconds),
SigningCredentials =
new SigningCredentials(new SymmetricSecurityKey(Key), SecurityAlgorithms.HmacSha512Signature),
Claims = roleClaims
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var ret = tokenHandler.WriteToken(token);
return ret;
}
Program.cs - SecurityService is added as singleton. Authentication, authorization used.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
SecurityService securityService = new(builder.Configuration);
builder.Services.AddDbContext<WorkItDbContext>();
builder.Services.AddSingleton<SecurityService>();
builder.Services.AddTransient<UserService>();
builder.Services.AddTransient<RoleService>();
builder.Services.AddTransient<OfferService>();
builder.Services.AddTransient<CategoryService>();
builder.Services.AddTransient<ResponseService>();
builder.Services.AddTransient<LocationService>();
builder.Services.AddCors();
builder.Services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(opt =>
{
var key = new SymmetricSecurityKey(securityService.Key);
opt.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = key,
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseSwagger();
app.UseSwaggerUI();
app.UseCors(options =>
options.WithOrigins("http://localhost:4200/").AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin());
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
CustomRoles.cs
public static class CustomRoles
{
public const string Admin = "ADMIN";
public const string Recruiter = "RECUITER";
public const string User = "USER";
}
UserController.cs
[HttpGet("All")]
[Authorize(Roles = CustomRoles.Admin "," CustomRoles.User "," CustomRoles.Recruiter)]
public async Task<IActionResult> GetUsers()
{
return Ok(await _userService.GetUsers());
}
Role.cs
public class Role
{
public Role()
{
Users = new HashSet<User>();
}
public long RoleId { get; set; }
public string? Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Images
CodePudding user response:
I reproduced your issue about the 401 error.
In my side it's related with the SigningCredentials
defined in the SecurityService
and the IssuerSigningKey
defined in Program.cs
.
You used RandomNumberGenerator.GetBytes(128)
to generate a Key
and use it to set SigningCredentials
and define the IssuerSigningKey
. And when I used a hardcode Key, it worked for me.
I used IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisismySecretKey"))
in the Program.cs
and SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisismySecretKey")), SecurityAlgorithms.HmacSha512Signature)
in SecurityService
.
Therefore, I compared the value of the key used in Program.cs
and SecurityService
, I found they don't have the same value. So I recommend you trying to hardcode the key first for testing, then check if it worked for you.