ASP.NET Core(MVC)使用Windows身份验证时如何给指定用户发送SignalR通知
解决方案
现有方案调整即可实现,无需获取HubConnectionContext
你配置的CustomUserIdProvider本身是可用的,你的核心误区是不需要手动调用IUserIdProvider.GetUserId()方法:该方法是SignalR框架内部在客户端建立Hub连接时自动调用的,用于将连接与对应用户ID绑定,你在业务代码中不需要主动调用。
操作步骤
- 首先确保你已经在服务注册逻辑中注入了自定义的用户ID提供器:
// Startup.cs 或 Program.cs services.AddSingleton<IUserIdProvider, CustomUserIdProvider>();
- 控制器中直接获取目标用户的Windows身份用户名即可,分两种场景:
- 给当前发起POST请求的用户发通知:直接读取控制器内置的
User属性即可,该值和CustomUserIdProvider返回的用户ID完全一致:
// API控制器内的代码 var targetUserId = User.Identity?.Name; if (!string.IsNullOrEmpty(targetUserId)) { await _myHub.Clients.User(targetUserId).SendAsync("ReceiveMessage", message); }
- 给其他指定用户发通知:直接传入目标用户的Windows用户名(格式为
域\用户名或机器名\用户名,和Identity.Name返回格式一致即可)。
替代方案
如果需要更灵活的通知控制,可以选择以下方案:
- 按组发送:在Hub的
OnConnectedAsync生命周期方法中,将当前连接加入对应用户名的分组:
public override async Task OnConnectedAsync() { var userName = Context.User.Identity?.Name; if (!string.IsNullOrEmpty(userName)) { await Groups.AddToGroupAsync(Context.ConnectionId, userName); } await base.OnConnectedAsync(); }
发通知时直接调用对应分组即可:
await _myHub.Clients.Group("目标用户名").SendAsync("ReceiveMessage", message);
- 自行维护用户-连接映射表:用线程安全的字典存储所有用户的活跃连接ID,在Hub的连接/断开连接生命周期中更新映射,发通知时先查询目标用户的所有连接ID,再批量发送:
// 全局线程安全字典 public static readonly ConcurrentDictionary<string, List<string>> UserConnectionMap = new(); // Hub内连接时添加 public override async Task OnConnectedAsync() { var userName = Context.User.Identity?.Name; if (!string.IsNullOrEmpty(userName)) { UserConnectionMap.AddOrUpdate(userName, _ => new List<string> { Context.ConnectionId }, (_, list) => { list.Add(Context.ConnectionId); return list; }); } await base.OnConnectedAsync(); } // 断开连接时移除 public override async Task OnDisconnectedAsync(Exception exception) { var userName = Context.User.Identity?.Name; if (!string.IsNullOrEmpty(userName) && UserConnectionMap.TryGetValue(userName, out var connections)) { connections.Remove(Context.ConnectionId); if (connections.Count == 0) { UserConnectionMap.TryRemove(userName, out _); } } await base.OnDisconnectedAsync(exception); }
控制器发消息代码:
if (UserConnectionMap.TryGetValue("目标用户名", out var connections)) { await _myHub.Clients.Clients(connections).SendAsync("ReceiveMessage", message); }
注意事项
- 需确保SignalR的Hub端点启用了Windows身份验证,禁止匿名访问,否则连接上下文中的用户身份会为空。
- 前端建立SignalR连接时需开启凭证携带配置,例如JS端创建
HubConnection时设置withCredentials: true。
内容的提问来源于stack exchange,提问作者diego esteban
相关产品推荐
相关产品推荐

