将角色添加到用户[JwtAuthentication]时不会添加角色声明

问题描述 投票:0回答:1

我正在尝试向我的 aspnetcore 后端添加基于角色的授权。 例如,我想要一个可以访问不同端点的“主持人”角色。 为此,我尝试使用本教程的一些内容:AspnetCore Identity Roles。 我现在遇到的问题是,当我将用户添加到角色并使用

[Authorize(Role="Moderator]
属性时,它不起作用,我总是得到 403。

测试用例示例:

[Fact]
public async Task It_should_return_404_for_non_existing_movies()
{
    using var scope = _factory.Services.CreateScope();
    var userManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
    var arrangeContext = scope.ServiceProvider.GetRequiredService<MovieDBContext>();

    await userManager.CreateAsync(
    new IdentityUser { UserName = "Mod", Email = "[email protected]" }, "mod12345");

    var mod = await userManager.FindByNameAsync("Mod");
    await userManager.AddToRoleAsync(mod!, "Moderator");

    var token = await _client.LoginAsync("[email protected]", "mod12345");

    _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await _client.DeleteAsync($"/movies/1337");
    response.StatusCode.Should().Be(HttpStatusCode.NotFound); // This fails because User.Claims does not contain role moderator
}

端点正在测试中调用(仍在开发中):

[HttpDelete("{id}"), Authorize(Roles = "Moderator")]
public IActionResult DeleteMovie(int id)
{
    var movie = _context.Movies.Find(id);
    if (movie == null)
    {
        return NotFound();
    }

    _context.Movies.Remove(movie);
    _context.SaveChanges();
    return Ok();
}

Startup.cs,我在其中添加了 aspnetcore 身份和身份验证内容:

services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(config =>
    {
        config.TokenValidationParameters = new TokenValidationParameters
        {
            ClockSkew = TimeSpan.Zero,
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"),
            ValidAudience = Configuration.GetValue<string>("JwtSettings:Audience"),
            IssuerSigningKey =
                new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:Key")!)),
        };
    });

services.AddAuthorization();


services
    .AddIdentityCore<IdentityUser>(options =>
    {
        options.SignIn.RequireConfirmedAccount = false;
        options.User.RequireUniqueEmail = true;
        options.Password.RequireDigit = false;
        options.Password.RequiredLength = 6;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = false;
        options.Password.RequireLowercase = false;
     })
     .AddRoles<IdentityRole>()
     .AddEntityFrameworkStores<UserContext>();

UserContext.cs:

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace MovieDatabase.Identity;
public class UserContext : IdentityDbContext<IdentityUser, IdentityRole, string>
{
    public UserContext(DbContextOptions<UserContext> options)
        : base(options)
    {
    }
    protected override void OnConfiguring(DbContextOptionsBuilder options)
    {
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<IdentityRole>()
            .HasData(
                new[] {
                    new IdentityRole { Name = "Admin", NormalizedName = "ADMIN" },
                    new IdentityRole { Name = "Moderator", NormalizedName = "MODERATOR" },
                    new IdentityRole { Name = "User", NormalizedName = "USER" } }
            );

        base.OnModelCreating(modelBuilder);
    }
}

在这里我还添加了我现在想要使用迁移支持的角色。 如果我检查像我在测试中所做的那样创建的用户的声明,这就是结果:

[
  {
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "value": "TokenForTheApiWithAuth"
  },
  {
    "type": "jti",
    "value": "2b9fb336-50b2-4569-845d-6c596eed39a2"
  },
  {
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "value": "080291d2-03b3-40dd-ac39-1793ba7e7b0d"
  },
  {
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
    "value": "test"
  },
  {
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
    "value": "[email protected]"
  },
  {
    "type": "exp",
    "value": "1697668413"
  },
  {
    "type": "iss",
    "value": "http://localhost:5278"
  },
  {
    "type": "aud",
    "value": "http://localhost:5253"
  }
]

AspNet用户表:

AspNetRoles 表:

AspNetUserRoles 表:

如上所示,我的用户已连接到数据库中的角色,如果我使用 UserManager 询问用户是否获得“主持人”角色,它将返回 true,但角色声明仍然缺失(参见上面的 JSON) 。 我在这个问题上被困了几天,也许有些人看到了我错过的东西。

我尝试了很多不同的事情,例如: 大多数解决方案都可以在这里找到Github Issue 在我发现这个堆栈溢出问题之后:问题

还尝试了这个问题的解决方案,例如在

.AddRoleManager(RoleManager<IdentityRole)
中添加
statup.cs
或添加
services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, UserClaimsPrincipalFactory<IdentityUser, IdentityRole>>();

但是在将用户添加到角色时,似乎没有任何东西可以将角色声明添加到用户。

包含所有代码的 Github 存储库:https://github.com/alexanderluettig/movie-database/tree/main

c# asp.net-mvc asp.net-core authorization asp.net-identity
1个回答
0
投票

因此,在 @Rena 发表评论后,当使用

JwtAuthentication
时,创建 jwt 令牌时不会自动添加角色声明。我在 Tokenservice.cs

中创建 Jwt 令牌时手动添加了它们

我添加的行是:

var roles = _userManager.GetRolesAsync(user).Result;
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
© www.soinside.com 2019 - 2024. All rights reserved.