【问题标题】:UserId in SignalR CoreSignalR 核心中的用户 ID
【发布时间】:2018-01-05 09:25:36
【问题描述】:

我正在将 SignalR 与 ASP.NET Core 2.0 一起使用,我正在尝试为特定用户发送通知,如下所示:

_notification.Clients.User(id).InvokeAsync("SendMes");

其中 _notification 是 IHubContext。 但它不起作用。当我为所有用户发送通知时,一切都很好,所有用户都会收到通知。但是当我将它发送给特定用户时,什么也没有发生。在连接中,我需要用户,但似乎他没有 userId。那么我该怎么做呢?通过访问身份和声明?如果是这样,该怎么做?

【问题讨论】:

  • 意外地,User(id) 通过电子邮件查找用户...是我的用户身份有问题还是其他问题?

标签: asp.net-core asp.net-core-signalr


【解决方案1】:

我遇到了类似的问题,以下文章帮助我解决了问题:https://docs.microsoft.com/en-us/aspnet/core/signalr/groups?view=aspnetcore-2.1

在集线器(服务器端)中,我检查了 Context.UserIdentifier 并且它为空,即使用户已通过身份验证。事实证明,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 用户和组区分大小写。

【讨论】:

    【解决方案2】:

    问题是我创建了与 cookie 一起使用的 ClaimsIdentity 对象,如下所示:

    new ClaimsIdentity(claims, "ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
    

    DefaultNameClaimType 是我的电子邮件地址。当我将“ClaimsIdentity.DefaultNameClaimType”更改为“ClaimsTypes.NameIdentifier”这是我的用户 ID 时,所有代码都可以正常使用:

    _notification.Clients.User(id).InvokeAsync("SendMes");
    

    【讨论】:

      【解决方案3】:

      如果使用 JWT,则必须在 SecurityTokenDescriptor 中添加 NameIdentifier Claim:

      new Claim(ClaimTypes.NameIdentifier, userId)
                 
      

      【讨论】:

        【解决方案4】:

        作为@Chris 提供的答案的附录,IUserIdProviderDefaultUserIdProvider 实现实际上是使用TryAdd*() 方法添加的。

        services.TryAddSingleton(typeof(IUserIdProvider), typeof(DefaultUserIdProvider));
        

        因此,您所要做的就是在调用 services.AddSignalR() 之前添加您自己的 IUserIdProvider 自定义实现,SignalR 会在看到您的时跳过添加自己的实现。

        services.AddSingleton<Microsoft.AspNetCore.SignalR.IUserIdProvider, MyCustomUserIdProvider>();
        services.AddSignalR();
        

        【讨论】:

          【解决方案5】:

          用户 ID 提供程序默认使用 IPrincipal.Identity.Name,对于大多数身份部署,最终是电子邮件地址。在较旧的 SignalR 中,这可以使用您自己的提供程序进行自定义。

          您只需实现以下接口:

          public interface IUserIdProvider
          {
              string GetUserId(IRequest request);
          }
          

          然后通过以下方式附加它:

          GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => new MyIdProvider());
          

          我不确定核心版本中有多少变化。 IUserIdProvider 仍然存在,只是界面略有变化:

          public interface IUserIdProvider
          {
              string GetUserId(HubConnectionContext connection);
          }
          

          当您在ConfigureServices 中调用AddSignalR 时,它当然会设置以下内容:

          services.AddSingleton(typeof(IUserIdProvider), typeof(DefaultUserIdProvider));
          

          DefaultUserIdProvider 显然是默认实现。似乎没有任何配置选项可以覆盖它,因此如果您需要使用自己的提供程序,则必须替换服务描述符:

          services.Replace(ServiceDescriptor.Singleton(typeof(IUserIdProvider), 
                                                       typeof(MyCustomUserIdProvider)));
          

          显然,这需要在致电AddSignalR 之后进行。另外,请注意,您必须先配置身份验证,然后再配置 SignalR。否则,用户将无法访问中心。

          【讨论】:

          猜你喜欢
          • 2018-02-28
          • 1970-01-01
          • 2018-09-21
          • 2019-08-18
          • 1970-01-01
          • 1970-01-01
          • 2019-10-08
          • 2019-07-19
          • 2019-07-18
          相关资源
          最近更新 更多