这是一个使用 IClaimsTransformation 的替代方案(使用 .NET 6)
几点说明:
在 ClaimsTransformer 类中,必须克隆现有的 ClaimsPrincipal 并将您的 Claims 添加到 那个,而不是尝试修改现有的 ClaimsPrincipal。然后必须在 ConfigureServices() 中将其注册为单例。
在 mheptinstall 的回答中使用的设置 AccessDeniedPath 的技术在这里不起作用,相反我必须使用 UseStatusCodePages() 方法来重定向到自定义页面以解决 403 错误。
必须使用newIdentity.RoleClaimType 类型创建新声明,而不是System.Security.Claims.ClaimTypes.Role,否则 AuthorizeAttribute(例如[Authorize(Roles = "Admin")])将不起作用
显然应用程序将设置为使用 Windows 身份验证。
ClaimsTransformer.cs
public class ClaimsTransformer : IClaimsTransformation
{
// Can consume services from DI as needed, including scoped DbContexts
public ClaimsTransformer(IHttpContextAccessor httpAccessor) { }
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
// Clone current identity
var clone = principal.Clone();
var newIdentity = (ClaimsIdentity)clone.Identity;
// Get the username
var username = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier || c.Type == ClaimTypes.Name).Value;
if (username == null)
{
return principal;
}
// Get the user roles from the database using the username we've just obtained
// Ideally these would be cached where possible
// ...
// Add role claims to cloned identity
foreach (var roleName in roleNamesFromDatabase)
{
var claim = new Claim(newIdentity.RoleClaimType, roleName);
newIdentity.AddClaim(claim);
}
return clone;
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddAuthorization();
services.AddSingleton<IClaimsTransformation, ClaimsTransformer>();
services.AddMvc().AddRazorRuntimeCompilation();
// ...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStatusCodePages(async context => {
if (context.HttpContext.Response.StatusCode == 403)
{
context.HttpContext.Response.Redirect("/Home/AccessDenied");
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
示例 HomeController.cs
[Authorize]
public class HomeController : Controller
{
public HomeController()
{ }
public IActionResult Index()
{
return View();
}
[Authorize(Roles = "Admin")]
public IActionResult AdminOnly()
{
return View();
}
[AllowAnonymous]
public IActionResult AccessDenied()
{
return View();
}
}