ASP.NET Core无要求项创建IAuthorization策略的方法及问题咨询
核心结论
直接在if(result)分支中标记所有待处理要求为成功不可行,会完全破坏ApiScope策略的验证逻辑,导致该策略的RequireClaim("scope", "customScope")要求被绕过,失去作用。
问题原因
ASP.NET Core的授权机制中,当你同时应用多个策略(如这里的ApiScope和ValidateGroups)时,所有策略的所有要求(Requirement)会被汇总到context.PendingRequirements中。你的GroupsValidationHandler实现了通用的IAuthorizationHandler接口,没有指定处理特定要求,因此会拦截所有待处理要求。一旦你的组验证通过,就会把包括ApiScope策略中scope声明验证在内的所有要求都标记为成功,这意味着哪怕用户没有customScope声明,只要组验证通过,ApiScope策略也会被判定为有效,完全违背了该策略的设计初衷。
正确解决方案
要避免干扰其他策略的验证逻辑,你需要让GroupsValidationHandler只处理属于自己的自定义要求,而非所有要求。具体步骤如下:
1. 创建自定义授权要求
定义一个专属的Requirement,用于标识组验证的逻辑边界:
public class GroupsValidationRequirement : IAuthorizationRequirement { // 可根据需求添加属性,比如指定必须存在的组列表等 }
2. 修改授权处理器,仅处理自定义要求
继承AuthorizationHandler<TRequirement>而非直接实现IAuthorizationHandler,这样处理器只会响应GroupsValidationRequirement:
public class GroupsValidationHandler : AuthorizationHandler<GroupsValidationRequirement> { private readonly IServiceScopeFactory _serviceScopeFactory; public GroupsValidationHandler(IServiceScopeFactory serviceScopeFactory) { _serviceScopeFactory = serviceScopeFactory; } protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, GroupsValidationRequirement requirement) { using (var scope = _serviceScopeFactory.CreateScope()) { var authService = scope.ServiceProvider.GetRequiredService<IAuthenticationService>(); var userGroups = context.User.FindAll("groups").Select(x => x.Value).ToList(); var result = await authService.AllGroupsExist(userGroups); if (result) { // 仅标记当前自定义要求为成功 context.Succeed(requirement); } else { // 组验证失败时终止授权流程 context.Fail(); if (context.Resource is DefaultHttpContext httpContext) { httpContext.Response.OnStarting(() => { httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; return Task.CompletedTask; }); } } } } }
3. 更新策略配置,绑定自定义要求
修改ValidateGroups策略,明确添加自定义要求,确保处理器只作用于该策略:
builder.Services.AddScoped<IAuthorizationHandler, GroupsValidationHandler>(); builder.Services.AddAuthorization(options => { options.AddPolicy("ApiScope", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("scope", "customScope"); }); options.AddPolicy("ValidateGroups", policy => { policy.RequireAuthenticatedUser(); // 将自定义要求绑定到该策略 policy.AddRequirements(new GroupsValidationRequirement()); }); options.InvokeHandlersAfterFailure = false; }); app.MapControllers().RequireAuthorization("ApiScope", "ValidateGroups");
效果说明
修改后,两个策略的验证逻辑完全独立:
ApiScope策略由ASP.NET Core默认的处理器验证用户是否认证、是否持有customScope声明;ValidateGroups策略由你的自定义处理器验证用户组是否全部存在;- 只有两个策略的所有要求都通过时,授权才会成功,任何一个策略失败都会直接返回401(因
InvokeHandlersAfterFailure = false,失败后不会继续调用其他处理器)。
内容的提问来源于stack exchange,提问作者nnchvxx

