ASP.NET中无需求的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
相关产品推荐
相关产品推荐

