You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SignalR Core按用户名发消息异常:Context.User.Identity.Name始终为空

解决SignalR Hub中Context.User.Identity.Name为空的问题

咱们一步步拆解问题,找到核心原因并逐个解决:

1. 修复JWT Claim与Identity.Name的映射

Context.User.Identity.Name默认会读取ClaimTypes.Name类型的Claim,但你生成Token时并未添加该Claim——虽然你配置了UniqueName、NameId等字段,但ASP.NET Core不会自动将这些映射到Identity.Name。

修改你的Token生成方法,补充ClaimTypes.Name的声明:

private TokenResponse generateToken(User user) { 
    var tokenHandler = new JwtSecurityTokenHandler(); 
    var key = Encoding.ASCII.GetBytes(_jwtSettings.Secret); 
    var tokenDescriptor = new SecurityTokenDescriptor { 
        Subject = new System.Security.Claims.ClaimsIdentity(new[] { 
            new Claim(JwtRegisteredClaimNames.Aud, user.Email), 
            new Claim(JwtRegisteredClaimNames.Sub, user.Email), 
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), 
            new Claim(JwtRegisteredClaimNames.Email, user.Email), 
            new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),
            new Claim(JwtRegisteredClaimNames.NameId, user.UserName), 
            new Claim(ClaimTypes.NameIdentifier,user.UserName), 
            // 新增这一行,将用户名映射到Identity.Name
            new Claim(ClaimTypes.Name, user.UserName)
        }), 
        Expires = DateTime.UtcNow.AddMinutes(10), 
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256) 
    }; 
    var token = tokenHandler.CreateToken(tokenDescriptor); 
    TokenResponse response = new TokenResponse(); 
    response.token = tokenHandler.WriteToken(token); 
    return response; 
}

2. 修正UserIdProvider的类名拼写错误

你定义的UserIdProvider类是CustomUserIdProvider,但在Startup注册时写的是CustomUserProvider(少了Id后缀),这会导致SignalR无法加载正确的用户ID解析器:

// 原错误代码
services.AddSingleton<IUserIdProvider, CustomUserProvider>();
// 修改为正确类名
services.AddSingleton<IUserIdProvider, CustomUserIdProvider>();

3. 调整中间件执行顺序(关键!)

中间件顺序直接影响身份验证和跨域逻辑的有效性,你的当前配置存在两处问题:

  • UseCors必须放在路由和身份验证之前,否则跨域请求的身份信息无法被正确识别
  • ASP.NET Core 3.x推荐使用UseEndpoints统一映射路由和SignalR Hub,避免UseSignalR和UseMvc的冲突

修改Configure方法:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { 
    if (env.IsDevelopment()) { 
        app.UseDeveloperExceptionPage(); 
    } 

    app.UseHttpsRedirection();

    // 跨域中间件放在最前面,确保所有请求都能处理跨域逻辑
    app.UseCors(x => x 
        .AllowAnyOrigin() 
        .AllowAnyMethod() 
        .AllowAnyHeader());

    app.UseRouting(); 

    app.UseAuthentication(); 
    app.UseAuthorization(); 

    // 统一用Endpoints映射控制器和SignalR Hub
    app.UseEndpoints(endpoints => { 
        endpoints.MapControllers(); 
        endpoints.MapHub<NotificationHub>("/myHub");
    }); 

    // 移除UseSignalR和UseMvc,避免路由冲突
    // app.UseSignalR(routes => { routes.MapHub<NotificationHub>("/myHub"); });
    // app.UseMvc(routes => { ... });
}

4. 规范JWT验证参数配置

你的JWT验证参数同时设置了ValidateAudience = false和ValidAudience,这会导致验证逻辑混乱。如果不需要验证Audience,直接移除ValidAudience配置;如果需要验证,则将ValidateAudience设为true并确保Token中的Aud字段与配置一致:

x.TokenValidationParameters = new TokenValidationParameters { 
    ValidateIssuerSigningKey = true, 
    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.Secret)), 
    ValidateIssuer = false, 
    ValidateAudience = false,
    // 移除冲突的配置项
    // ValidIssuer = Configuration["JwtSettings:Issuer"], 
    // ValidAudience = Configuration["JwtSettings:Issuer"], 
    RequireExpirationTime = true, // 开启过期时间验证,提升安全性
    ClockSkew = TimeSpan.FromMinutes(60), 
    ValidateLifetime = true, 
};

5. 客户端Token传递验证

确保Android客户端连接SignalR时,正确将JWT Token作为access_token参数附加到连接URL中,示例格式:
wss://your-domain.com/myHub?access_token=your-jwt-token-string

完成以上所有步骤后,重新生成Token并测试,Hub中的Context.User.Identity.Name就能正确获取到用户名,Clients.User(name).SendAsync也可以正常按用户名发送消息了。

内容的提问来源于stack exchange,提问作者Haytham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 21:37:31