SignalR Core 无法与Cookie认证协同工作问题求助
看起来你遇到的核心问题是SignalR Hub无法获取已认证的用户身份——虽然HTTP请求的认证流程正常,但Hub连接建立后身份信息就丢失了。结合你的代码,我整理了几个关键修复点:
1. 不要用IHttpContextAccessor获取Hub的用户身份
SignalR的连接在握手阶段(HTTP请求)完成后,后续的Hub方法调用是基于WebSocket的持久连接,不再经过完整的HTTP管道。IHttpContextAccessor只能获取当前HTTP请求的上下文,而Hub本身提供了Context.User属性,专门用于获取当前连接的用户身份。修改你的TestHub:
public class TestHub: Hub { public override async Task OnConnectedAsync() { // 直接使用Hub自带的Context.User,而非IHttpContextAccessor bool isAuthenticated = Context.User.Identity.IsAuthenticated; await Task.FromResult(1); } [Authorize] public Task SendAuth(string message) { return Clients.All.InvokeAsync("SendAuth", message + " Authed"); } // ...其他方法 }
2. 修正认证中间件的配置和顺序
你的Startup里AddAuthentication()没有指定默认认证方案,虽然AddIdentity会自动添加Cookie认证,但明确配置默认方案能避免SignalR识别认证方式时出错:
在ConfigureServices中修改:
// 替换原来的services.AddAuthentication(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; });
另外,自定义中间件的位置建议调整到UseAuthentication之后——你的中间件是在_next(context)之后检查用户身份,放在认证之后能确保你看到的是经过认证后的上下文:
在Configure中调整顺序:
if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // 先执行认证中间件 app.UseAuthentication(); // 再执行自定义中间件 app.UseMiddleware<MyMiddleware>(); // 最后挂载SignalR app.UseSignalR(routes => { routes.MapHub<TestHub>("TestHub"); }); app.UseMvc(routes => { routes.MapRoute(name: "default", template: "{controller=App}/{action=Index}/{id?}"); });
3. 确保WebSocket请求正确传递Cookie
客户端使用HttpClientHandler的CookieContainer是正确的,但要确认HubConnection在建立WebSocket连接时确实携带了认证Cookie。如果你的客户端和服务器存在跨域(哪怕是端口不同),还需要配置CORS允许携带凭证:
在ConfigureServices中添加CORS配置:
services.AddCors(options => { options.AddPolicy("SignalRCors", builder => { builder.WithOrigins("http://localhost:5000") // 替换成你的客户端实际地址 .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); // 关键:允许携带Cookie等凭证 }); });
然后在Configure中启用CORS(要放在UseAuthentication之后,UseSignalR之前):
app.UseCors("SignalRCors");
4. 明确SignalR Hub的认证方案(可选)
如果上面的步骤仍未解决问题,可以在映射Hub时明确指定认证方案,强制SignalR使用Cookie认证:
app.UseSignalR(routes => { routes.MapHub<TestHub>("TestHub").RequireAuthorization(options => { options.AuthenticationSchemes = new[] { CookieAuthenticationDefaults.AuthenticationScheme }; }); });
按照这些步骤修改后,Hub应该就能正确获取已认证的用户身份,调用[Authorize]标记的方法也不会再出现授权失败的问题了。
内容的提问来源于stack exchange,提问作者Craigt

