You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core授权:如何获取首个失败要求并终止检查?策略是否适用?

两种解决方案供你选择

方案1:为每个要求创建专属策略(推荐,更直观易维护)

如果你的核心需求是明确知晓哪项要求失败,同时可以灵活控制验证顺序和终止逻辑,为每个IAuthorizationRequirement单独创建策略是最清晰的方案。

注册策略示例

services.AddAuthorization(options =>
{
    options.AddPolicy("FooPolicy", policy => policy.AddRequirements(new FooRequirement()));
    options.AddPolicy("BarPolicy", policy => policy.AddRequirements(new BarRequirement()));
    options.AddPolicy("YetAnotherPolicy", policy => policy.AddRequirements(new YetAnotherRequirement()));
});

手动按顺序验证(失败即终止)

// 先验证Foo要求
var fooAuthResult = await _authorizationService.AuthorizeAsync(User, resource, "FooPolicy");
if (!fooAuthResult.Succeeded)
{
    // 记录FooRequirement失败,直接返回,终止后续检查
    var failedFooReq = fooAuthResult.Failure?.FailedRequirements.FirstOrDefault();
    // 这里可以处理失败逻辑,比如返回对应提示
    return;
}

// 再验证Bar要求
var barAuthResult = await _authorizationService.AuthorizeAsync(User, resource, "BarPolicy");
if (!barAuthResult.Succeeded)
{
    // 记录BarRequirement失败,终止后续
    var failedBarReq = barAuthResult.Failure?.FailedRequirements.FirstOrDefault();
    return;
}

// 最后验证YetAnother要求
var yetAnotherAuthResult = await _authorizationService.AuthorizeAsync(User, resource, "YetAnotherPolicy");
if (!yetAnotherAuthResult.Succeeded)
{
    var failedYetAnotherReq = yetAnotherAuthResult.Failure?.FailedRequirements.FirstOrDefault();
    return;
}

// 所有要求都通过,继续业务逻辑

这种方式的好处是:

  • 每个策略职责单一,便于测试和维护
  • 完全控制验证顺序,失败时能精准定位到具体是哪项要求没通过
  • 可以灵活调整验证逻辑(比如某些要求是可选的,或者按不同顺序验证)

方案2:自定义顺序执行的授权处理器(保留单一策略)

如果你希望保留一个统一的SomePolicy,但需要实现“失败即终止”的逻辑,可以自定义一个IAuthorizationHandler,按顺序逐个验证要求,一旦失败就停止后续处理。

自定义顺序处理器示例

public class SequentialAuthorizationHandler : IAuthorizationHandler
{
    private readonly IEnumerable<IAuthorizationHandler> _allHandlers;

    // 注入系统中所有已注册的授权处理器
    public SequentialAuthorizationHandler(IEnumerable<IAuthorizationHandler> allHandlers)
    {
        _allHandlers = allHandlers;
    }

    public async Task HandleAsync(AuthorizationHandlerContext context)
    {
        // 按策略中添加的顺序处理每个未完成的要求
        foreach (var requirement in context.PendingRequirements.ToList())
        {
            // 找到对应要求的处理器
            var handler = _allHandlers.FirstOrDefault(h => 
                h.GetType().IsAssignableTo(typeof(IAuthorizationHandler<>).MakeGenericType(requirement.GetType())));

            if (handler == null)
            {
                // 如果找不到对应处理器,标记失败并终止
                context.Fail(new AuthorizationFailureReason(this, $"No handler found for {requirement.GetType().Name}"));
                break;
            }

            // 执行当前要求的验证
            await handler.HandleAsync(context);

            // 如果当前要求未通过,终止后续所有验证
            if (!context.HasSucceeded)
            {
                break;
            }
        }
    }
}

注册自定义处理器

// 注册自定义顺序处理器
services.AddScoped<IAuthorizationHandler, SequentialAuthorizationHandler>();

// 仍然保留你的原策略注册
services.AddAuthorization(options => 
{ 
    options.AddPolicy("SomePolicy", policy => 
    { 
        policy.AddRequirements(new FooRequirement()); 
        policy.AddRequirements(new BarRequirement()); 
        policy.AddRequirements(new YetAnotherRequirement()); 
    }); 
});

这种方式的好处是可以保留单一策略,但需要额外编写自定义处理器,复杂度比方案1高一些。


总结
  • 现有默认策略机制无法满足你“失败即终止并定位具体失败项”的需求
  • 推荐优先选择方案1(每个要求一个策略),代码更清晰、易维护,也更灵活
  • 如果必须保留单一策略,可以用**方案2(自定义顺序处理器)**实现需求

内容的提问来源于stack exchange,提问作者Pierre Roudaut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:55:54