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

如何解决SignalR中基于Cookie的身份验证HttpContext.User为空问题

问题:SignalR Hub中HttpContext.User为空的排查与解决

背景情况

我有一个Asp.Net Core Web API + Angular前端的项目,已配置基于Cookie的身份验证,在Web API控制器中访问HttpContext.User能正常获取用户信息。项目基于Asp.Net Core Identity实现身份识别与授权。

当前认证配置代码:

services.AddAuthentication(opt =>
        {
            opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,

                ValidIssuer = tokenSettings.ValidIssuer,
                ValidAudience = tokenSettings.ValidAudience,
                IssuerSigningKey =
                    new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenSettings.SecurityKey))
            };
        });

中间件配置:

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

为了验证用户是否有权限打开对应资源的SignalR WebSocket,我重写了Hub的OnConnectedAsync方法:

public override async Task OnConnectedAsync()
{
    string dashboardId = Context.GetHttpContext().Request.Query["dashboardId"];
    string connectionId = Context.ConnectionId;
    await _mediator.Send(new StartDashboardDataAcquisitionCommand(Context.GetHttpContext().User, Guid.Parse(dashboardId)));

    await base.OnConnectedAsync();
}

客户端初始化代码:

this.connection = new signalR.HubConnectionBuilder()
  .withUrl(environment.backendUrl + 'dashboards/data?dashboardId=' + dashboardId)
  .withAutomaticReconnect()
  .build();

this.connection.on('SendDashboardData', dataBatch => {
  this.store.dispatch(new SetActiveDashboardData(dataBatch as DataBatch));
});
this.connection.start().catch(err => {
  console.error(err);
});

问题:命令处理器验证权限时,发现Context.GetHttpContext().User为空,浏览器不是会自动发送Cookie吗?请问遗漏了什么配置?


排查与解决

核心矛盾点

你的认证配置是JWT Bearer认证方案,但你实际使用的是Cookie身份验证,两者不匹配。系统只会按照默认的JWT Bearer方案去解析请求中的令牌,不会处理Cookie中的身份信息,导致SignalR连接请求未被正确认证,User对象为空。

具体解决步骤

  1. 调整认证方案配置,匹配Cookie认证
    如果你用Asp.Net Core Identity,默认的认证方案是Cookie(IdentityConstants.ApplicationScheme),需要修改默认认证方案为Cookie:

    services.AddAuthentication(opt =>
    {
        opt.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        opt.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
    })
    // 若需同时支持JWT,可保留JWT配置,但默认方案设为Cookie
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
    
            ValidIssuer = tokenSettings.ValidIssuer,
            ValidAudience = tokenSettings.ValidAudience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenSettings.SecurityKey))
        };
    });
    

    注:Asp.Net Core Identity调用AddIdentity/AddDefaultIdentity时会自动添加Cookie认证,无需手动AddCookie,只需确保默认方案正确。

  2. 确保跨域场景下允许携带凭据
    如果前端和后端是跨域部署,需配置CORS允许凭据,并在前端SignalR连接中开启withCredentials:

    • 后端CORS配置:
      services.AddCors(options =>
      {
          options.AddPolicy("AllowAngular", policy =>
          {
              policy.WithOrigins(environment.FrontendUrl)
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials(); // 必须开启,允许携带Cookie
          });
      });
      // 中间件顺序:UseCors必须在UseAuthentication之前
      app.UseCors("AllowAngular");
      
    • 前端SignalR配置:
      this.connection = new signalR.HubConnectionBuilder()
        .withUrl(environment.backendUrl + 'dashboards/data?dashboardId=' + dashboardId, {
          withCredentials: true // 携带Cookie凭据
        })
        .withAutomaticReconnect()
        .build();
      
  3. 检查中间件顺序
    中间件顺序必须严格遵循以下顺序,否则认证逻辑无法正常执行:

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors(); // 必须在认证之前
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapHub<YourDashboardHub>("/dashboards/data"); // 确保Hub路由正确配置
    });
    
  4. 简化Hub中用户信息的获取
    SignalR的Hub.Context直接包含用户信息,无需通过GetHttpContext()获取,可直接使用Context.User:

    public override async Task OnConnectedAsync()
    {
        string dashboardId = Context.GetHttpContext().Request.Query["dashboardId"];
        await _mediator.Send(new StartDashboardDataAcquisitionCommand(Context.User, Guid.Parse(dashboardId)));
    
        await base.OnConnectedAsync();
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:25:56