连接SignalR Hub时HandleAuthenticateAsync多次调用,HTTP请求仅调用1次
问题原因
- SignalR 原生协商机制导致多请求触发认证
SignalR 建立连接前默认会先发送negotiate协商请求获取可用传输协议、连接ID等信息,该请求会触发一次认证;协商成功后会发起实际传输协议(如WebSocket)的握手请求,再次触发认证,因此.NET客户端默认会出现2次认证调用。
非.NET客户端(如浏览器端JS客户端)跨域访问时,协商请求前会先发送CORS OPTIONS预检请求,该请求也会触发认证逻辑,最终形成OPTIONS预检 → negotiate协商 → 传输握手3次请求,对应3次认证调用。 - 中间件配置错误放大问题
你当前的中间件顺序存在两处错误:
UseAuthentication放在了UseRouting之前,认证中间件会在路由匹配前执行,所有请求无论是否匹配到SignalR/接口路由都会触发认证- 重复调用
UseEndpoints,会导致路由匹配逻辑重复执行,进一步增加不必要的认证调用
解决方法
第一步:修正中间件配置
调整中间件顺序为ASP.NET Core官方推荐顺序,合并UseEndpoints调用:
app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod() ); // 先执行路由匹配,再处理认证 app.UseRouting(); app.UseAuthentication(); // 若有授权中间件需放在认证之后 // app.UseAuthorization(); // 合并端点映射,不要分开调用 app.UseEndpoints(endpoints => { endpoints.MapHub<MasterHub>("/connect"); endpoints.MapControllers(); });
第二步:跳过OPTIONS预检请求的认证
在FbigAuthenticationHandler的HandleAuthenticateAsync方法开头增加预检请求跳过逻辑:
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { // 直接跳过CORS预检请求的认证校验 if (Request.Method == HttpMethods.Options) { return AuthenticateResult.NoResult(); } // 原有认证逻辑保留 // ... }
第三步(可选):关闭协商阶段进一步减少调用
如果确认所有客户端都仅使用WebSocket传输协议,可以在客户端配置关闭协商,仅保留一次WebSocket握手请求的认证:
.NET客户端配置示例:
var hubConnection = new HubConnectionBuilder() .WithUrl("你的Hub连接地址", options => { // 仅当固定使用WebSocket时可开启 options.SkipNegotiation = true; options.Transports = HttpTransportType.WebSockets; // 其余认证配置保留 }) .Build();
内容的提问来源于stack exchange,提问作者Adam Q
相关产品推荐
相关产品推荐

