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

ASP.NET中无需求的Authorization Handler如何调用context.Succeed()?

问题:Authorization Handler中调用context.Succeed()的困惑

我实现了如下的Authorization Handler:

public class StationToIDMMatchHandler : IAuthorizationHandler
{
    private readonly IHttpContextAccessor _httpContextAccessor = null;
    private readonly AftermarketDbContext _db;

    public StationToIDMMatchHandler(IHttpContextAccessor httpContextAccessor, AftermarketDbContext db)
    {
        _httpContextAccessor = httpContextAccessor;
        _db = db;
    }


    public Task HandleAsync(AuthorizationHandlerContext context)
    {
        HttpContext httpContext = _httpContextAccessor.HttpContext; // Access context here

        string StationUniqueId = httpContext.Request.Headers.Where(x => x.Key == " StationUniqueId").FirstOrDefault().Value;

        var listOfRoles = context.User.Claims.Where(c => c.Type == "groups").Select(x => x.Value).ToList();

        string requiredIDMRole = _db.StationRole.Where(DbStationUniqueId => DbStationUniqueId.StationId == StationUniqueId).ToString();


        if (listOfRoles.Contains(requiredIDMRole))
        {
            context.Succeed();
            return Task.CompletedTask;
        }
        else
            return Task.CompletedTask;
    }
}

但我除了已校验的逻辑外没有其他需求,无法调用无参的context.Succeed()。请问该如何处理?是否必须创建实现IAuthorizationRequirement的空类?这似乎不是好方法。


解决方案

方法一:创建空Requirement类(官方标准方案)

这是ASP.NET Core授权系统的设计要求——context.Succeed()必须接收一个IAuthorizationRequirement实例,用来标记对应的授权要求已通过。你只需要定义一个最简单的空类即可:

public class StationToIDMMatchRequirement : IAuthorizationRequirement { }

接着修改Handler,继承泛型的AuthorizationHandler<StationToIDMMatchRequirement>而非直接实现IAuthorizationHandler,这样就能在HandleRequirementAsync方法中调用带参数的context.Succeed(requirement):

public class StationToIDMMatchHandler : AuthorizationHandler<StationToIDMMatchRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly AftermarketDbContext _db;

    public StationToIDMMatchHandler(IHttpContextAccessor httpContextAccessor, AftermarketDbContext db)
    {
        _httpContextAccessor = httpContextAccessor;
        _db = db;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, StationToIDMMatchRequirement requirement)
    {
        HttpContext httpContext = _httpContextAccessor.HttpContext;
        // 修正Header键的空格问题,同时处理空值
        string stationUniqueId = httpContext.Request.Headers["StationUniqueId"].FirstOrDefault()?.Trim();

        if (string.IsNullOrEmpty(stationUniqueId))
        {
            context.Fail();
            return Task.CompletedTask;
        }

        var userRoles = context.User.Claims.Where(c => c.Type == "groups").Select(x => x.Value).ToList();
        // 修正原代码的错误:Where+ToString会输出SQL,应该用FirstOrDefault获取实体
        var stationRole = _db.StationRole.FirstOrDefault(s => s.StationId == stationUniqueId);
        
        if (stationRole != null && userRoles.Contains(stationRole.RoleName)) // 假设RoleName是存储角色的字段
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }
}

最后在Program.cs/Startup.cs中注册授权策略和Handler:

services.AddAuthorization(options =>
{
    options.AddPolicy("StationToIDMMatch", policy =>
        policy.Requirements.Add(new StationToIDMMatchRequirement()));
});

services.AddScoped<IAuthorizationHandler, StationToIDMMatchHandler>();

方法二:遍历现有Requirements(不推荐的取巧方式)

如果你实在不想创建空Requirement类,可以在HandleAsync中遍历context.Requirements,取任意一个实例传入context.Succeed()。但这种方式属于绕过框架设计的技巧,可读性和可维护性差,不建议在生产环境使用:

public Task HandleAsync(AuthorizationHandlerContext context)
{
    HttpContext httpContext = _httpContextAccessor.HttpContext;
    string stationUniqueId = httpContext.Request.Headers["StationUniqueId"].FirstOrDefault()?.Trim();

    if (string.IsNullOrEmpty(stationUniqueId))
        return Task.CompletedTask;

    var userRoles = context.User.Claims.Where(c => c.Type == "groups").Select(x => x.Value).ToList();
    var stationRole = _db.StationRole.FirstOrDefault(s => s.StationId == stationUniqueId);

    if (stationRole != null && userRoles.Contains(stationRole.RoleName))
    {
        var requirement = context.Requirements.FirstOrDefault();
        if (requirement != null)
        {
            context.Succeed(requirement);
        }
    }

    return Task.CompletedTask;
}

原代码的关键问题修正

  • 读取Header时,原代码中键带有空格" StationUniqueId",容易导致匹配失败,建议统一去掉空格或用Trim()处理
  • _db.StationRole.Where(...).ToString()会返回SQL语句而非实际角色值,必须改用FirstOrDefault()获取实体后取对应字段
  • 增加空值判断,避免空引用异常导致程序崩溃

内容的提问来源于stack exchange,提问作者Mr.Gomer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 05:40:33