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

标签 c# .net-core jwt asp.net-core-3.1 asp.net-core-identity

我遇到一个问题,当我尝试在 Controller 中使用 [Authorize(Roles = "Administrator")] 时,它总是返回 403。我正在使用身份和 JWT token 。这是我的 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();
    });
}

这是我创建 token 的方法

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);
}

我在我的 Controller 上添加这样的内容

[Route("api/[controller]")]
[ApiController]
[Authorize]
public class ProfileController : ControllerBase
{
    [HttpGet]
    [Authorize(Roles = "Administrator")]
    public async Task<IActionResult> Get()
    {
        return Ok();
    }
}

这是我的 JWT token 有效负载!

{
  "user_role": "Administrator",
  "user_id": "5a6333f1-9696-4b1c-a8f8-04619ebd686d",
  "name": "Admin Admin",
  "completed_profile": "False",
  "email": "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="89e4f0e8ede4e0e7ece4e8e0e5c9eee4e8e0e5a7eae6e4" rel="noreferrer noopener nofollow">[email protected]</a>",
  "nbf": 1597147248,
  "exp": 1597233648,
  "iat": 1597147248
}

最佳答案

我遇到了类似的问题,我通过将 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
};

关于c# - .NET Core 3.1 基于角色的 JWT 授权返回 403 禁止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63356429/

相关文章:

asp.net-core - 从配置文件配置 JwtBearerOptions

cryptography - .Net Core中的RNGCryptoServiceProvider

authentication - 我需要在哪里使用 JWT?

c# - Azure:通过证书从云工作人员连接到 key 保管库

c# - "dotnet build"的 C#8 命令行编译器的最小安装

python - 哪个 Python JOSE 库支持嵌套 JWT(签名+加密)?

python - x5t JWT 指纹 Python 转换

c# - 为什么 Logging 不使用字符串插值

Java Double setScale 和 RoundingMode 在 C# 中等效吗?

c# - 如何使用 SevenZipSharp 创建 SFX ZIP?