我正在使用 SignalR Core,由于架构原因,SignalR 服务器内容(集线器等)与我的主项目位于不同的域中。 客户有这个代码:
function connectToHub(url) {
var connection = new signalR.HubConnectionBuilder()
.withUrl(url, { headers: { "cookie": document.cookie } }).build();
connection.on("NotificationUpdated", function (count) {
console.log(count);
});
connection.start().then(function () {
console.log('started');
}).catch(function (err) {
return console.error(err.toString());
});
}
它可以正常连接到服务器,但我的中心中的 OnConnectedAsync 没有获取 cookie 或任何其他凭据(Context.User.Identity.Claims 为空)
这是 OnConnectedAsync 代码
public async override Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, ((ClaimsIdentity)Context.User.Identity)
.Claims.FirstOrDefault(c => c.Type.Contains("email"))?.Value);
await base.OnConnectedAsync();
}
如果我将集线器放在与客户端相同的域中,它工作正常,但如果我将它放在不同的域中,客户端将停止附加cookie。
如何让客户端附加cookie?
(或者,如果有不同的方式将 connectionId 与用户声明映射,我也可以接受)
我在 Blazor Server(Cookie 身份验证)中遇到了与此问题类似的问题,经过大量搜索后,我找不到任何有用的内容。尽管如此,我还是设法以某种方式做到了,但我不确定这是否是最好的,甚至是一个好方法。
1- 在 razor 页面中注入 IHttpContextAccessor。
@inject IHttpContextAccessor HttpContextAccessor
2-从 IHttpContextAccessor 读取所有 cookie 并将它们添加到连接 cookie。
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, // Set the domain of the cookie
Path = uri.Path // Set the path of the cookie
});
}
})
.Build();
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
var encodedMsg = $"{user}: {message}";
messages.Add(encodedMsg);
InvokeAsync(StateHasChanged);
});
await hubConnection.StartAsync();
}
3- 现在您可以使用 AuthorizeAttribute 装饰您的中心。
[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);
}
}