Blazor Server(Cookie认证)中SignalR为何无法自动向服务器发送Cookie?
微软文档提到:
在基于浏览器的应用中,Cookie认证允许现有用户凭据自动流转到SignalR连接。使用浏览器客户端时无需额外配置,若用户已登录应用,SignalR连接会自动继承该认证。
Cookie是浏览器特有的访问令牌传递方式,但非浏览器客户端也可使用。使用.NET客户端时,可在.WithUrl调用中配置Cookies属性来提供Cookie,但从.NET客户端使用Cookie认证需要应用提供用于交换认证数据获取Cookie的API。
但实际在Blazor Server的Razor页面中,按文档描述的自动继承认证未生效,我通过以下方式实现了Cookie传递,但不确定是否最优,求更好的方案:
当前实现步骤
- 在Razor页面注入
IHttpContextAccessor
@inject IHttpContextAccessor HttpContextAccessor
- 从
IHttpContextAccessor读取所有Cookie并添加到SignalR连接配置中
protected override async Task OnInitializedAsync() { var uri = new UriBuilder(Navigation.Uri); hubConnection = new HubConnectionBuilder() .WithUrl(Navigation.ToAbsoluteUri("/chathub"), opti => { if (HttpContextAccessor.HttpContext != null) foreach (var c in HttpContextAccessor.HttpContext.Request.Cookies) { opti.Cookies.Add(new Cookie(c.Key, c.Value) { Domain = uri.Host, // 设置Cookie的域名 Path = uri.Path // 设置Cookie的路径 }); } }) .Build(); hubConnection.On<string, string>("ReceiveMessage", (user, message) => { var encodedMsg = $"{user}: {message}"; messages.Add(encodedMsg); InvokeAsync(StateHasChanged); }); await hubConnection.StartAsync(); }
- 给Hub添加
[Authorize]特性
[Authorize] public class ChatHub : Hub { public override Task OnConnectedAsync() { return base.OnConnectedAsync(); } public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
更优实现方案
当前实现虽可行,但存在两处明显问题:
- 手动复制所有Cookie会引入不必要的Cookie,增加请求体积
- 直接依赖
IHttpContextAccessor在Blazor Server中可能存在线程安全风险(组件会在不同线程上渲染)
实际上,Blazor Server中SignalR客户端可以自动继承当前用户的认证Cookie,无需手动复制,只需确保以下两点:
- Blazor Server应用已正确配置Cookie认证(默认
Program.cs中已配置) - 创建
HubConnection时使用默认配置即可:
protected override async Task OnInitializedAsync() { hubConnection = new HubConnectionBuilder() .WithUrl(Navigation.ToAbsoluteUri("/chathub")) .Build(); hubConnection.On<string, string>("ReceiveMessage", (user, message) => { var encodedMsg = $"{user}: {message}"; messages.Add(encodedMsg); InvokeAsync(StateHasChanged); }); await hubConnection.StartAsync(); }
若自动传递仍不生效,大概率是以下原因:
- SignalR Hub地址与Blazor应用不在同一域名下(跨域场景),需配置CORS允许携带Cookie
- 应用Cookie配置中
SameSite=None未搭配HTTPS使用,或SameSite设置过于严格
若确实需要手动传递特定Cookie(而非全部),可优化代码仅传递认证相关Cookie(如.AspNetCore.Identity.Application),减少请求负载:
.WithUrl(Navigation.ToAbsoluteUri("/chathub"), opti => { if (HttpContextAccessor.HttpContext?.Request.Cookies.TryGetValue(".AspNetCore.Identity.Application", out var authCookie) ?? false) { opti.Cookies.Add(new Cookie(".AspNetCore.Identity.Application", authCookie)); } })
另外,Blazor Server中使用IHttpContextAccessor时,建议在OnAfterRenderAsync中访问,或利用HttpContextAccessor.HttpContext.RequestAborted令牌确保线程安全,避免OnInitializedAsync阶段HttpContext未完全初始化的问题。
内容的提问来源于stack exchange,提问作者Vahid Borhani

