我正在尝试向我的 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"
}
]
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
因此,在 @Rena 发表评论后,当使用
JwtAuthentication
时,创建 jwt 令牌时不会自动添加角色声明。我在 Tokenservice.cs 中创建 Jwt 令牌时手动添加了它们
我添加的行是:
var roles = _userManager.GetRolesAsync(user).Result;
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));