我正在使用带有Asp.Net核心2.0的SignalR,我正在尝试为特定用户发送通知,如下所示:
_notification.Clients.User(id).InvokeAsync("SendMes");
其中_notification是IHubContext。但它不起作用。当我发送所有用户的通知时,一切都很好,所有用户都会收到通知。但是当我将它发送给特定用户时,没有任何反应。在连接中我需要用户,但好像他没有userId。那我该怎么做呢?通过访问身份和声明?如果是这样怎么办?
问题是我创建了与cookies一起使用的ClaimsIdentity对象,如下所示:
new ClaimsIdentity(claims, "ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
DefaultNameClaimType是我的电子邮件。当我将'ClaimsIdentity.DefaultNameClaimType'更改为'claimTypes.NameIdentifier'这是我的用户ID时,所有这些都正常使用此代码:
_notification.Clients.User(id).InvokeAsync("SendMes");
我遇到了类似的问题,下面的文章帮助我解决了问题:https://docs.microsoft.com/en-us/aspnet/core/signalr/groups?view=aspnetcore-2.1
在Hub(服务器端)中,我检查了Context.UserIdentifier,它是null,即使用户已经过身份验证。事实证明,SignalR依赖于ClaimTypes.NameIdentifier,我只设置了ClaimTypes.Name。所以,基本上我添加了另一个声明并且它成功了(在此之后正确设置了Context.UserIdentifier)。
下面我分享一部分身份验证代码,以防它有所帮助:
var claims = userRoles.Split(',', ';').Select(p => new Claim(ClaimTypes.Role, p.Trim())).ToList();
claims.Insert(0, new Claim(ClaimTypes.Name, userName));
claims.Insert(1, new Claim(ClaimTypes.NameIdentifier, userName)); // this is the claim type that is used by SignalR
var userIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
请注意,SignalR用户和组区分大小写。
用户标识提供程序默认使用IPrincipal.Identity.Name
,对于大多数标识部署,最终都是电子邮件地址。在旧的SignalR中,可以使用您自己的提供商来定制。
您只需实现以下界面:
public interface IUserIdProvider
{
string GetUserId(IRequest request);
}
然后通过以下方式附加:
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => new MyIdProvider());
我不确定Core版本中有多少变化。 IUserIdProvider
仍然存在,虽然界面略有变化:
public interface IUserIdProvider
{
string GetUserId(HubConnectionContext connection);
}
当您在AddSignalR
中调用ConfigureServices
时,它会设置以下内容,当然还有以下内容:
services.AddSingleton(typeof(IUserIdProvider), typeof(DefaultUserIdProvider));
DefaultUserIdProvider
显然是默认实现。似乎没有任何配置选项可以覆盖它,因此如果您需要使用自己的提供程序,则必须替换服务描述符:
services.Replace(ServiceDescriptor.Singleton(typeof(IUserIdProvider),
typeof(MyCustomUserIdProvider)));
显然,这需要在调用AddSignalR
之后。另外,请注意在配置SignalR之前必须先配置auth。否则,用户将无法访问集线器。
作为@Chris提供的答案的附录。 DefaultUserIdProvider
的IUserIdProvider
实现实际上是使用TryAdd*()
方法添加的。
services.TryAddSingleton(typeof(IUserIdProvider), typeof(DefaultUserIdProvider));
因此,您需要做的就是在调用IUserIdProvider
之前添加自己的services.AddSignalR()
自定义实现,而SignalR会在看到你自己的时候跳过添加它自己。
services.AddSingleton<Microsoft.AspNetCore.SignalR.IUserIdProvider, MyCustomUserIdProvider>();
services.AddSignalR();