ASP.NET Core 6 Web API自定义特性传参 HubFilter执行异常问题
问题根因
你遇到的两个问题核心是混淆了SignalR全局Hub过滤器和MVC特性过滤器的运行逻辑:
- 调用
hubOptions.AddFilter<T>()是全局注册过滤器,注册后所有Hub的所有方法调用都会触发该过滤器,不会自动判断方法/类是否标注了对应特性,所以才会出现没打标记也执行的情况。 - 你额外封装的
RTProAuthorizationHubFilter属于多余的套娃层,全局注册时DI容器无法自动解析构造函数里的bool isAuthorization参数,同时你也没有在过滤器逻辑里判断特性标记,既导致参数传不进去,也导致过滤器全量执行。
修复方案
不需要保留RTProAuthorizationHubFilter包装类,直接调整RTProAuthorizationHubContext的逻辑,在过滤器内部自行判断当前调用的类/方法是否标记了特性,再决定是否执行授权逻辑即可。
第一步:修改RTProAuthorizationHubContext代码
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)] public class RTProAuthorizationHubContext : AuthorizeAttribute, IHubFilter { private readonly ISecurityService _securityService; private readonly IRTProAuthenticationService _rTProAuthenticationService; private readonly IUnitOfWork _unitOfWork; private readonly IOptions<AuthenticationSettingsInfo> _authenticationSettings; // 公开属性用于读取标记时传入的参数 public bool IsAuthorization { get; } // 注意:DI注入的参数放前面,自定义非注入参数放最后并设置默认值,避免DI解析报错 public RTProAuthorizationHubContext( ISecurityService securityService, IRTProAuthenticationService rTProAuthenticationService, IUnitOfWork unitOfWork, IOptions<AuthenticationSettingsInfo> authenticationSettings, bool isAuthorization = true ) { IsAuthorization = isAuthorization; _rTProAuthenticationService = rTProAuthenticationService; _authenticationSettings = authenticationSettings; _unitOfWork = unitOfWork; _securityService = securityService; } public async ValueTask<object> InvokeMethodAsync( HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next) { // 先查找当前执行方法上的特性,找不到再查找Hub类上的特性 var hubType = invocationContext.Hub.GetType(); var methodInfo = hubType.GetMethod(invocationContext.HubMethodName); var authAttr = methodInfo?.GetCustomAttribute<RTProAuthorizationHubContext>() ?? hubType.GetCustomAttribute<RTProAuthorizationHubContext>(); // 没有标记特性直接放行,不执行授权逻辑 if (authAttr == null) { return await next(invocationContext); } // 此处写你的授权逻辑,通过authAttr.IsAuthorization即可拿到标记时传入的参数值 // ...... 原有授权代码 return await next(invocationContext); } }
第二步:修改Program.cs中的SignalR注册
直接注册调整后的RTProAuthorizationHubContext即可,不需要注册之前的包装类:
builder.Services.AddSignalR(hubOptions => { hubOptions.EnableDetailedErrors = true; hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(1); hubOptions.AddFilter<RTProAuthorizationHubContext>(); });
第三步:在Hub类/方法上标记特性传参
直接在需要控制授权的类或方法上标记特性,传入isAuthorization参数即可:
// 类上标记,该Hub下所有方法默认开启授权 [RTProAuthorizationHubContext] public class BusinessHub : Hub { // 单独标记该方法,关闭授权校验 [RTProAuthorizationHubContext(isAuthorization: false)] public async Task PublicAccessMethod() { // 公开接口逻辑 } // 未单独标记的方法沿用类上的配置,开启授权校验 public async Task ProtectedMethod() { // 需授权接口逻辑 } }
内容的提问来源于stack exchange,提问作者Reza Yousefi
相关产品推荐
相关产品推荐

