求助:.NET Core 2.1 SignalR连接成功但客户端为null及用户身份为空
听起来你已经搞定了WebSocket连接,但卡在了消息推送这一步,还遇到了用户身份标识为空的问题——我之前处理过好几个类似的场景,咱们一步步来排查:
1. 先解决用户身份标识为空的核心问题
context.User.Identity.Name 为空,说明SignalR的Hub没有正确识别到已认证用户,这大概率是认证中间件配置缺失或者客户端未传递认证令牌导致的:
服务器端配置认证(Startup.cs)
如果你用JWT认证,需要在ConfigureServices里添加JWT Bearer认证,并且专门配置SignalR的令牌处理(因为WebSocket握手是GET请求,令牌通常放在Query参数里):
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = Configuration["Jwt:Issuer"], // 替换成你的实际配置 ValidAudience = Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])) }; // 处理SignalR的令牌传递逻辑 options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; var path = context.HttpContext.Request.Path; // 当请求路径指向SignalR Hub时,从Query参数获取令牌 if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs")) { context.Token = accessToken; } return Task.CompletedTask; } }; });
然后在Configure方法里,必须确保UseAuthentication()在UseSignalR()之前调用:
app.UseAuthentication(); app.UseSignalR(routes => { routes.MapHub<YourHub>("/hubs/yourhub"); // 替换成你的Hub实际路径 });
客户端(Ionic 3)传递令牌
连接SignalR时,要通过accessTokenFactory把令牌传递给服务器:
import { HubConnection, HubConnectionBuilder } from '@aspnet/signalr'; // 初始化SignalR连接 const connection = new HubConnectionBuilder() .withUrl('https://your-server-domain/hubs/yourhub', { accessTokenFactory: () => { // 从本地存储或认证服务获取你的JWT令牌 return localStorage.getItem('auth_token'); } }) .build();
你可以用浏览器开发者工具查看WebSocket的握手请求,确认Query参数里是否带有access_token,或者请求头里是否有Authorization: Bearer <token>。
2. 排查客户端消息接收的注册问题
如果服务器推送时客户端显示null,很可能是消息接收方法的名称不匹配(SignalR对方法名大小写敏感!):
比如服务器端调用:
await Clients.User(userId).SendAsync("ReceiveNotification", messageContent);
那客户端必须严格匹配方法名:
// 注意方法名要和服务器完全一致,包括大小写 connection.on('ReceiveNotification', (message) => { console.log('收到消息:', message); // 这里处理消息逻辑,比如更新页面UI });
如果方法名写错,客户端就找不到对应的处理函数,看起来就像消息是null。
3. 先做广播测试排除目标推送问题
你可以先放弃针对用户的推送,改用广播测试,确认基础的消息传递是否正常:
// 在服务器Hub的某个方法里调用广播 await Clients.All.SendAsync("TestBroadcast", "这是一条测试广播消息");
客户端注册对应的接收方法:
connection.on('TestBroadcast', (msg) => { console.log('收到广播:', msg); });
如果能收到广播,说明连接和消息传递的基础逻辑没问题,问题出在用户标识的关联上;如果还是收不到,那要检查:
- 客户端安装的SignalR版本是否和服务器兼容:.NET Core 2.1对应的客户端是
@aspnet/signalr@1.1.x,不要用新版的@microsoft/signalr - Hub的映射路径是否和客户端连接URL完全一致
- 客户端是否在连接成功后才注册接收方法(最好在
connection.start().then(...)的回调里注册)
最后再检查OnConnectedAsync的细节
在OnConnectedAsync里,你可以打印更多上下文信息来排查:
public override async Task OnConnectedAsync() { // 打印认证状态 Console.WriteLine($"用户是否认证:{Context.User.Identity.IsAuthenticated}"); // 打印请求的Query参数,确认令牌是否传递成功 foreach (var query in Context.Request.Query) { Console.WriteLine($"{query.Key}: {query.Value}"); } await base.OnConnectedAsync(); }
如果IsAuthenticated是false,那肯定是认证配置的问题,先把这个搞定,用户标识才能正常获取,针对用户的推送才能生效。
内容的提问来源于stack exchange,提问作者Thranor

