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

SignalR Hub加Authorize属性后JWT认证返回401问题排查

问题:Blazor Server结合Identity与SignalR时JWT认证及用户识别异常

我在Blazor Server项目中结合Identity使用SignalR,配置的JWT选项如下:

.AddJwtBearer(options => { 
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateAudience=false,
        ValidateIssuer=true,
        ValidateLifetime=true,
        ValidateIssuerSigningKey=true,
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience=builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["Jwt:Key"])),
    };
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];
            var path = context.HttpContext.Request.Path;
            if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/ConnectionsHub")))
            {
                context.Token = accessToken;
                context.Response.Headers.Authorization = accessToken;
            }
            return Task.CompletedTask;
        }
    };
})
...
builder.Services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
builder.Services.AddSingleton<IUserIdProvider, CustomEmailProvider>();

自定义IUserIdProvider代码:

public class CustomEmailProvider : IUserIdProvider
{
    public virtual string GetUserId(HubConnectionContext connection)
    {
        var res = connection.User?.Claims.FirstOrDefault(x=>x.Type==ClaimTypes.NameIdentifier);
        return res?.Value;
    }
}

遇到的问题:

  • 当Hub添加[Authorize]属性时,客户端连接返回401未授权
  • 不添加[Authorize]时,GetUserId返回null,且connection.User无任何Claims,无法识别Identity用户

可能的问题及修复方案

1. 重复注册IUserIdProvider导致服务冲突

同时注册NameUserIdProvider和CustomEmailProvider两个IUserIdProvider实现,DI容器只会保留最后注册的实例。核心问题是认证未通过导致connection.User为空,先移除重复注册,只保留自定义实现:

// 移除 builder.Services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
builder.Services.AddSingleton<IUserIdProvider, CustomEmailProvider>();

2. OnMessageReceived事件错误设置响应头

在事件中设置context.Response.Headers.Authorization属于错误操作,会干扰认证流程,仅需将提取到的令牌赋值给context.Token即可:

options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        var accessToken = context.Request.Query["access_token"];
        var path = context.HttpContext.Request.Path;
        if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/ConnectionsHub"))
        {
            context.Token = accessToken;
        }
        return Task.CompletedTask;
    }
};

3. TokenValidationParameters配置矛盾

设置ValidateAudience=false的同时指定ValidAudience会导致验证逻辑混乱,根据需求二选一:

  • 无需验证Audience:移除ValidAudience赋值
    ValidateAudience=false,
    // 去掉 ValidAudience=builder.Configuration["Jwt:Audience"],
    
  • 需要验证Audience:将ValidateAudience设为true,确保配置文件中Jwt:Audience值正确
    ValidateAudience=true,
    ValidAudience=builder.Configuration["Jwt:Audience"],
    

4. 中间件顺序错误

Blazor Server中认证中间件顺序必须正确,确保UseAuthentication和UseAuthorization在UseRouting之后,且在MapBlazorHub和MapHub之前:

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

app.MapBlazorHub();
app.MapHub<ConnectionsHub>("/ConnectionsHub");
app.MapFallbackToPage("/_Host");

5. 客户端令牌传递方式不正确

确保SignalR客户端通过AccessTokenProvider将令牌注入到请求查询参数中:

var hubConnection = new HubConnectionBuilder()
    .WithUrl(NavigationManager.ToAbsoluteUri("/ConnectionsHub"), options =>
    {
        options.AccessTokenProvider = () => Task.FromResult(yourJwtToken);
    })
    .Build();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:05:53