错误详情:
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler - Successfully validated the token.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService - Authorization failed. These requirements were not met:
RolesAuthorizationRequirement:User.IsInRole must be true for one of the following roles: (Admin)
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler - AuthenticationScheme: Bearer was forbidden.
Microsoft.AspNetCore.Hosting.Diagnostics - Request finished HTTP/2 POST https://localhost:8003/cfg.Cfg/RemoveCatgegory application/grpc - - 403 0 - 403.5567ms
JWT 配置:
services.AddAuthorization();
services.AddAuthentication();
#region JWT
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JWTSetting.SecurityKey));
o.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
ValidIssuer = JWTSetting.Issuer,
ValidAudience = JWTSetting.Audience,
IssuerSigningKey = key,
//生成Token 的时候,加密了, 这里需要解密
TokenDecryptionKey = key,
};
});
其中 RoleClaimType
用的是 JwtClaimTypes.Role
生成Token 配置:
if (user != null)
{
var expireAt = DateTime.Now.AddDays(30);
var tokenHandler = new JwtSecurityTokenHandler();
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JWTSetting.SecurityKey));
var encryptingCredentials = new EncryptingCredentials(key, JwtConstants.DirectKeyUseAlg, SecurityAlgorithms.Aes256CbcHmacSha512);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(JwtClaimTypes.Audience, JWTSetting.Audience),
new Claim(JwtClaimTypes.Issuer, JWTSetting.Issuer),
new Claim(JwtClaimTypes.Id, user.Account),
new Claim(JwtClaimTypes.Role, user.Role.ToString()),
new Claim("User", JsonSerializer.Serialize(user))
}),
Expires = expireAt,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature),
//加密
EncryptingCredentials = encryptingCredentials
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
var tokenInfo = new TokenInfo
{
Token = tokenString,
LoginOn = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime(DateTime.Now.ToUniversalTime()),
ExpiressAt = new DateTimeOffset(expireAt).ToUnixTimeSeconds(),
Name = user.Name,
OpenID = user.OpenID,
Succ = true,
};
return tokenInfo;
}
其中:Role
使用的是 JwtClaimTypes.Role
,和 JWT 配置中的 RoleClaimType
保持一致。
上面代码, 生成的 role
, 在写到 AccessToken 之前, 还是 JwtClaimTypes.Role
:
生成Token 之前,是 role:Admin
上面两张图显示, 生成 AccessToken 的时候, 就是 JwtClaimTypes.Role
但是, 用它生成的 AccessToken ,发送到服务器,却变成了:ClaimTypes.Role
搞不懂是哪里把 JwtClaimTypes.Role
给换成了 ClaimTypes.Role
的。
找了两天答案, 找到下面这段:
oauth 2.0 - Asp.net core token based claims authentication with OpenIdConnect and angularjs: Bearer was forbidden - Stack Overflow
policy.RequireClaim("role"); might not work OTB, as IdentityModel uses an internal mapping that converts well-known JWT claims to their ClaimTypes equivalent: here, role will be likely replaced by http://schemas.microsoft.com/ws/2008/06/identity/claims/role (ClaimTypes.Role). I'd recommend using policy.RequireRole("user") instead.
会将 JwtClaimTypes.Role
替换为等效的 ClaimTypes.Role
? 不懂是什么神仙操作。
即然是这样,那就把 JWT 配置中的 RoleClaimType 从 JwtClaimTypes.Role
改为 ClaimTypes.Role
o.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = ClaimTypes.Role,
...
把生成Token 配置中的:
new Claim(JwtClaimTypes.Role, user.Role.ToString()),
改为:
new Claim(ClaimTypes.Role, user.Role.ToString()),
在运行,通过。
网友评论