[英]ASP.NET Core 3.1 Web API Role based authorization not working
[英]Role based authorization in ASP.NET Core 3.1 with Identity and ExternalLogin
我是 .NET Core 的新手,我正在尝试在 .NET Core 3.1 项目中设置基于角色的授权。 我相信我点击了每个在线讨论它的教程和线程。 我的问题是它似乎很容易在教程上工作,但它对我不起作用。 根据我找到的教程,我所要做的就是为数据库中的用户分配一个角色,然后在控制器的操作之前使用[Authorize(Roles="roleName")]
。 当我这样做时,对于具有指定角色的用户,我总是会收到 403 错误。 当我使用userManager.GetRolesAsync(user)
时,我看到用户具有角色。 当我使用 [Authorize] 向此操作发出请求时,它会在用户登录时按预期工作。
我检查了当前用户的调试模式 ClaimsPrincipal.Identity ,我发现RoleClaimType = "role"
。 我检查了当前用户的声明,发现它没有“角色”类型的声明。 这就是[Authorize(Roles="...")]
工作原理吗? 它看起来像索赔吗? 如果是这样,我如何获得用户角色的声明? 用户登录此应用程序的唯一方法是使用 Google 帐户。 那么,如果它们由 Google 登录管理,我应该如何添加声明呢?
这是我在 Startup.cs 中的代码
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddGoogle(options =>
{
IConfigurationSection googleAuthNSection =
Configuration.GetSection("Authentication:Google");
options.ClientId = googleAuthNSection["ClientId"];
options.ClientSecret = googleAuthNSection["ClientSecret"];
})
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
这是 Controller 的操作示例
[Authorize(Roles = "Admin")]
[HttpGet("userinformations")]
public async Task<UserInformations> GetCurrentUserInformations()
{
string strUserId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
ApplicationUser user = await userManager.FindByIdAsync(strUserId);
string[] roles = (await userManager.GetRolesAsync(user)).ToArray();
UserInformations userInfo = new UserInformations()
{
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
Email = user.Email,
Organization = user.idDefaultOrganisation.HasValue ? user.DefaultOrganization.OrganizationName : "",
Claims = this.User.Claims.Select(c => $"{c.Type} : {c.Value}").ToArray(),
Roles = roles
};
return userInfo;
}
当我在没有 [Authorize(Roles = "Admin")] 的情况下向此操作发出请求时,我可以看到当前用户具有角色 Admin,但是当我添加它时,我收到 403 错误。
我究竟做错了什么? 我觉得我在某处遗漏了一行或类似的东西,因为在我找到的教程中这一切似乎都很简单。
您的假设是正确的,当您指定[Authorize(Roles = "<role>")]
属性时,ASP 将在幕后创建RolesAuthorizationRequirement
。
然后授权处理程序将调用this.HttpContext.User.IsInRole(<role>)
来评估策略。
在您的情况下,调用是this.HttpContext.User.IsInRole("Admin")
User.IsInRole
方法将查看名为"http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
的声明并将其值与“Admin”进行比较
ASP 授权管道未与您的 UserManager 逻辑挂钩,基本的 API 将仅观察和验证 JWT 令牌声明。
您可能应该创建自己的 AuthorizationHandler 来检查用户是否确实是管理员
或者使用 RequireAssertion 的不太正式的方式:
services.AddAuthorization(options => options.AddPolicy("Admininstrators", builder =>
{
builder.RequireAssertion(async context =>
{
string strUserId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await userManager.FindByIdAsync(strUserId);
string[] roles = (await userManager.GetRolesAsync(user)).ToArray();
return roles.Contains("Admin");
};
});
[Authorize("Admininstrators")]
[HttpGet("userinformations")]
public async Task<UserInformations> GetCurrentUserInformations()
{
...
}
我终于找到了一个可行的解决方案。 我尝试使用 RequireAssertion 调整 @MichaelShterenberg 的代码,但我无法让它工作,因为我必须查询我的数据库并且我无法将 UserManager 与此解决方案一起使用。 我最终根据他的回答的这一部分找到了解决方案:
您可能应该创建自己的 AuthorizationHandler 来检查用户是否确实是管理员
我遵循了这个线程的答案: DotNet Core 中 AuthorizationOptions Requirement 的依赖注入
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.