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

SignalR Hub中[Authorize]失效且无法获取Authorization请求头问题

问题修复方案

核心问题分析

  1. Token获取为null:SignalR JS客户端使用accessTokenFactory时,WebSocket协议下会将Token放在查询字符串的access_token参数中,而非Authorization请求头,直接读取Headers自然拿不到值。
  2. [Authorize]特性失效:JWT认证默认仅识别请求头中的Token,SignalR通过查询参数传Token时,认证中间件无法识别,导致授权失败;同时可能存在中间件顺序配置错误。

1. 配置JWT认证支持查询参数

在Program.cs(或Startup.cs)的认证配置中,修改JWTBearerOptions,添加对查询参数的支持:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        // 保留原有Token验证配置
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };

        // 添加SignalR Token解析逻辑
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                var accessToken = context.Request.Query["access_token"];
                var path = context.HttpContext.Request.Path;

                // 仅对SignalR Hub路径生效
                if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/users"))
                {
                    context.Token = accessToken;
                }
                return Task.CompletedTask;
            }
        };
    });

2. 简化Hub中UserId获取逻辑

[Authorize]生效后,直接从认证后的Context.User中读取Claims,无需手动解析Token:

// 替换原有GetUserIdFromToken方法
private string GetUserId()
{
    // 确保"id"与JWT生成时的Claim类型一致
    return Context.User.Claims.FirstOrDefault(c => c.Type == "id")?.Value;
}

// 在OnConnectedAsync/OnDisconnectedAsync中调用
var userId = GetUserId();

3. 修正中间件顺序

确保Program.cs中中间件顺序正确:

app.UseAuthentication(); // 认证中间件必须在前
app.UseAuthorization();  // 授权中间件紧随其后
app.MapHub<UsersHub>("/users"); // SignalR Hub映射最后配置

4. 客户端验证Token传递

添加日志确认Token不为空:

var token = this.jwtService.getJwtToken();
console.log("SignalR Token:", token); // 确认Token有效

this.hubConnection = new signalR.HubConnectionBuilder()
    .withUrl(`${environment.apiURL}/users`, { accessTokenFactory: () => token })
    .build();

额外注意事项

  • 若使用长轮询协议,accessTokenFactory会自动将Token放入Authorization头,但WebSocket受浏览器限制只能用查询参数。
  • 先移除自定义的[UserSession]特性测试,确认[Authorize]生效后再重新添加。
  • 跨域场景下,确保CORS配置允许SignalR请求携带查询参数。

内容的提问来源于stack exchange,提问作者Ãfsħąl Ãtħąr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:32:02