ASP.NET Core Identity:如何直接基于Claims而非Policy实现授权
实现直接通过Claim检查的自定义授权方案
这个需求我之前也碰到过,完全不用写几百个重复的Policy,我们可以利用ASP.NET Core授权系统的**需求(Requirement)+处理器(Handler)**机制,配合自定义的Authorize属性来实现你要的[Authorize(Claim = "Key1")]效果,具体步骤如下:
1. 定义自定义授权需求
首先创建一个需求类,用来传递我们要检查的Claim类型:
public class ClaimExistsRequirement : IAuthorizationRequirement { // 要检查的Claim类型(也就是你的密钥名称) public string ClaimType { get; } public ClaimExistsRequirement(string claimType) { ClaimType = claimType ?? throw new ArgumentNullException(nameof(claimType)); } }
2. 实现授权处理器
接下来写一个处理器类,负责检查当前用户是否拥有指定的Claim:
public class ClaimExistsHandler : AuthorizationHandler<ClaimExistsRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ClaimExistsRequirement requirement) { // 检查用户是否包含目标Claim if (context.User.HasClaim(claim => claim.Type == requirement.ClaimType)) { // 验证通过,标记需求已满足 context.Succeed(requirement); } // 如果验证不通过,不需要主动调用Fail(),授权系统会自动返回未授权 return Task.CompletedTask; } }
3. 创建自定义Authorize属性
现在我们要做一个可以直接在Controller/Action上标记的属性,让它把需求传递给授权系统:
public class AuthorizeClaimAttribute : AuthorizeAttribute, IAuthorizationData { // 暴露一个ClaimType属性,用来指定要检查的密钥名称 public string ClaimType { get; set; } public IEnumerable<IAuthorizationRequirement> GetRequirements() { if (string.IsNullOrEmpty(ClaimType)) { throw new InvalidOperationException("必须为AuthorizeClaimAttribute指定ClaimType!"); } // 返回我们定义的需求 yield return new ClaimExistsRequirement(ClaimType); } }
4. 注册授权服务
在你的Program.cs(.NET 6+)或者Startup.cs中,注册我们的处理器:
// .NET 6+ Program.cs示例 var builder = WebApplication.CreateBuilder(args); // 添加MVC服务(如果用的是API就加AddControllers) builder.Services.AddControllersWithViews(); // 配置授权系统,并注册自定义处理器 builder.Services.AddAuthorization() .AddScoped<IAuthorizationHandler, ClaimExistsHandler>(); var app = builder.Build(); // ...其他中间件配置 app.UseAuthorization(); app.MapControllers(); app.Run();
5. 在Controller中使用
现在你就可以像你想要的那样,直接在Controller或Action上标记检查指定的Claim了:
public class SecretController : Controller { // 检查用户是否拥有Key1这个密钥对应的Claim [AuthorizeClaim("Key1")] public IActionResult AccessWithKey1() { return View(); } // 同时检查多个Claim(默认是逻辑与,用户需要同时拥有这两个Claim才能访问) [AuthorizeClaim("Key1"), AuthorizeClaim("Key2")] public IActionResult AccessWithBothKeys() { return View(); } }
额外说明
- 如果需要逻辑或的检查(比如用户拥有Key1或Key2就能访问),可以稍微修改处理器,或者创建一个支持多Claim的需求类,不过你的场景里单个检查应该足够了。
- 确保你的用户ClaimsPrincipal中已经正确添加了对应的密钥Claim(比如登录时从数据库读取用户的密钥列表,添加到Claims里)。
内容的提问来源于stack exchange,提问作者Pietro
相关产品推荐
相关产品推荐

