AuthenticationScheme: Bearer was

2021-01-29  本文已影响0人  gruan

错误详情:

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
生成Token 之前,是 role:Admin

上面两张图显示, 生成 AccessToken 的时候, 就是 JwtClaimTypes.Role

但是, 用它生成的 AccessToken ,发送到服务器,却变成了:ClaimTypes.Role

QQ图片20210129163510.png

搞不懂是哪里把 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()),

在运行,通过。

上一篇下一篇

猜你喜欢

热点阅读