.NET Core 3.1 基于角色的 JWT 授权返回 403 禁止

Posted

技术标签:

【中文标题】.NET Core 3.1 基于角色的 JWT 授权返回 403 禁止【英文标题】:.NET Core 3.1 role-based authorization with JWT returns 403 forbidden 【发布时间】:2020-12-01 00:23:16 【问题描述】:

我遇到了一个问题,当我尝试在我的控制器中使用 [Authorize(Roles = "Administrator")] 时,它总是返回 403。我正在使用身份和 JWT 令牌。这是我的Startup.cs。我在ConfigureServices() 中同时调用app.UseAuthentication()app.UseAuthorization(),但每次返回403 时仍然相同

public void ConfigureServices(IServiceCollection services)

    ...
    services.AddIdentity<User, Role>(options =>
    
        options.Password.RequireDigit = false;
        options.Password.RequireLowercase = false;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = false;
        options.Password.RequiredUniqueChars = 0;
        options.Password.RequiredLength = 6;

        options.ClaimsIdentity.UserIdClaimType = "user_id";
        options.ClaimsIdentity.UserNameClaimType = "email";
        options.ClaimsIdentity.RoleClaimType = "user_role";
    )
        .AddRoles<Role>()
        .AddEntityFrameworkStores<MyDbContext>()
        .AddDefaultTokenProviders();

    var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JwtKey"].ToString());

    services.AddAuthentication(options =>
    
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    )
    .AddJwtBearer(options => 
        options.RequireHttpsMetadata = false;
        options.SaveToken = false;
        options.TokenValidationParameters = new TokenValidationParameters
        
            ValidateIssuerSigningKey = true,
            ValidateAudience = false,
            ValidateIssuer = false,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ClockSkew = TimeSpan.Zero
        ;

        options.Events = new JwtBearerEvents
        
            OnAuthenticationFailed = context =>
            
                context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;

                return Task.CompletedTask;
            
        ;
    );

    services.AddControllers()
        .AddNewtonsoftJson(options =>
        
            options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
            options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        );
...


public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

    if (env.IsDevelopment())
    
        app.UseDeveloperExceptionPage();
    

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthentication();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    
        endpoints.MapControllers();
    );

这是我创建令牌的方式

private async Task<string> GenerateToken(DataModelUser user)

    var key = Encoding.UTF8.GetBytes(_appSettings.JwtKey);
    var tokenDescriptor = new SecurityTokenDescriptor
    
        Subject = new ClaimsIdentity(new Claim[]
        
            new Claim("user_role", user.Role.ToString()),
            new Claim("user_id", user.Id.ToString()),
            new Claim("email", user.Email)
        ),
        Expires = DateTime.UtcNow.AddDays(1),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    ;

    var tokenHandler = new JwtSecurityTokenHandler();
    var securityToken = tokenHandler.CreateToken(tokenDescriptor);

    return tokenHandler.WriteToken(securityToken);

我在我的控制器上添加这样的内容

[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ProfileController : ControllerBase

    [HttpGet]
    [Authorize(Roles = "Administrator")]
    public async Task<IActionResult> Get()
    
        return Ok();
    

这是我的 JWT 令牌负载!


  "user_role": "Administrator",
  "user_id": "5a6333f1-9696-4b1c-a8f8-04619ebd686d",
  "name": "Admin Admin",
  "completed_profile": "False",
  "email": "myadminemail@gmail.com",
  "nbf": 1597147248,
  "exp": 1597233648,
  "iat": 1597147248

【问题讨论】:

嗨@Erlan。您是在检查角色“管理员”还是“管理员”?由于在上面的帖子中您提到要检查“管理员”,而在控制器示例中您要检查“管理员”。 @ThomasLuijken 抱歉,写错了,因为我正在检查Administrator,现在编辑问题! @Erlan,好的,感谢您的更新。只是为了检查我们没有遗漏任何明显的东西。我希望在这两个地方设置 'user_role' 声明可以解决问题,但显然它没有。您能否将 JWT 令牌中的一部分有效负载也上传到票证中,以便我们可以看到您的令牌的实际内容是什么样的?您可以在jwt.io 处粘贴访问令牌以查看实际有效负载。 @ThomasLuijken 是的,当然,刚刚编辑了问题并从 JWT 令牌添加了有效负载。 【参考方案1】:

我有一个类似的问题,我通过将 RoleClaimType 和 NameClaimType 添加到 TokenValidationParameter 来解决它:

options.TokenValidationParameters = new TokenValidationParameters

    ValidateIssuerSigningKey = true,
    ValidateAudience = false,
    ValidateIssuer = false,
    IssuerSigningKey = new SymmetricSecurityKey(key),
    ClockSkew = TimeSpan.Zero,
    RoleClaimType = IdentityModel.JwtClaimTypes.Role,
    NameClaimType = IdentityModel.JwtClaimTypes.Name
;

【讨论】:

谢谢,使用 RoleClaimType 解决了我的问题

以上是关于.NET Core 3.1 基于角色的 JWT 授权返回 403 禁止的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core WebApi Jwt 基于角色的授权不起作用

手把手教你 .NET Core 3.1 JWT身份认证

ASP.NET Core 3.1 中基于角色的授权,带有 Identity 和 ExternalLogin

ASP.NET Core 2.2 JWT 身份验证

NET Core 3.1 MVC 授权/身份验证,带有在单独的 Net Core 3.1 Web Api 中从外部获取的令牌 (JWT)

控制器无法识别 JWT 角色.net core 5