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

Blazor Server中为客户端配置服务端SignalR身份标识(JWT/Cookie)

问题说明

已实现JWT认证,但登录后SignalR服务端无法识别客户端Identity;使用Cookie认证时,创建HubConnectionBuilder后服务端同样无法识别客户端身份。已配置SignalR通过用户ID(邮箱/名称)识别用户,自定义了IUserIdProvider实现,且Hub已添加[Authorize]特性。

自定义IUserIdProvider代码:

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

一、JWT认证场景修复

SignalR的WebSocket连接无法自动携带Authorization请求头,需要在服务端配置JwtBearer支持从查询参数提取Token,同时客户端手动传入Token。

1. 服务端Program.cs配置修改

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => { 
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateAudience=true,
        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"])),
    };

    // 新增:适配SignalR的WebSocket连接,从查询参数提取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;
        }
    };
});

2. 客户端Hub连接代码修改

protected override async Task OnInitializedAsync()
{
    if (hub is null)
    {
        // 从本地存储获取已登录的JWT Token(根据实际存储方式调整)
        var token = await _localStorage.GetItemAsync<string>("authToken");

        hub = new HubConnectionBuilder()
            .WithUrl(_NavigationManager.ToAbsoluteUri("/ConnectionsHub"), options =>
            {
                // 配置Token提供者,自动将Token加入查询参数
                options.AccessTokenProvider = () => Task.FromResult(token);
            })
            .Build();
    }
    // 启动Hub连接
    await hub.StartAsync();
}

二、Cookie认证场景修复

Cookie认证下需确保服务端CORS允许携带凭证,客户端连接时明确包含Cookie。

1. 服务端CORS配置修改

builder.Services.AddCors(options => options.AddDefaultPolicy(builder =>
    builder.AllowAnyHeader()
           .AllowAnyMethod()
           .AllowCredentials() // 必须开启,允许携带Cookie
           .SetIsOriginAllowed(origin => true) // 替代AllowAnyOrigin,避免和AllowCredentials冲突
));

2. 客户端Hub连接代码修改

protected override async Task OnInitializedAsync()
{
    if (hub is null)
    {
        hub = new HubConnectionBuilder()
            .WithUrl(_NavigationManager.ToAbsoluteUri("/ConnectionsHub"), options =>
            {
                // 明确允许携带Cookie凭证
                options.Credentials = HttpCredentialsInclude.Include;
            })
            .Build();
    }
    await hub.StartAsync();
}

三、优化自定义IUserIdProvider

当前实现逻辑冗余,可简化为直接获取Identity的Name(确保认证时该声明已正确包含):

public class CustomEmailProvider : IUserIdProvider
{
    public string GetUserId(HubConnectionContext connection)
    {
        // 直接返回已认证用户的Identity名称(邮箱/用户名)
        return connection.User?.Identity?.Name;
    }
}

四、额外检查点

  • 生成JWT Token时,确保包含ClaimTypes.Name或ClaimTypes.NameIdentifier声明,示例:
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, user.Email),
        // 其他必要声明
    };
    
  • 保持服务端中间件顺序正确:UseRouting → UseCors → UseAuthentication → UseAuthorization → UseEndpoints
  • 在Hub方法中添加调试代码,检查身份解析情况:
    public async Task TestAuth()
    {
        Console.WriteLine($"IsAuthenticated: {Context.User.Identity.IsAuthenticated}");
        foreach(var claim in Context.User.Claims)
        {
            Console.WriteLine($"{claim.Type}: {claim.Value}");
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:03:30