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

ASP.NET授权无法识别SignalR CONNECT请求中的JWT Bearer令牌

问题分析与解决方案

你遇到的这个情况不少开发者都碰过,核心问题大概率出在IConfigureNamedOptions的配置范围或者SignalR请求的特殊处理逻辑上,下面给你拆解原因和解决办法:

可能的原因

  1. 命名选项匹配问题
    如果你实现IConfigureNamedOptions<JwtBearerOptions>时,只针对特定名称的选项做了配置(比如只处理了name为"CustomBearer"的情况),但SignalR默认使用的是名为"Bearer"的JWT认证方案,这就会导致SignalR的请求对应的JwtBearerOptions没有被你的配置覆盖,自然不会触发OnMessageReceived的逻辑。

  2. SignalR请求路径未被识别
    你的OnMessageReceived逻辑可能没有针对SignalR的CONNECT请求路径做判断,导致即使查询字符串里有access_token,也没被赋值给context.Token。毕竟SignalR的请求路径一般是/hubs/xxx这类,和普通API路径不同,如果你的逻辑里没有匹配这个路径前缀,就会跳过处理。

  3. 中间件顺序错误
    如果JWT Bearer认证中间件是在SignalR中间件之后添加的,那么SignalR的CONNECT请求会先经过SignalR中间件,此时还没完成认证,就会触发授权质询。

解决办法

1. 确保IConfigureNamedOptions覆盖默认认证方案的选项

实现IConfigureNamedOptions<JwtBearerOptions>时,要同时处理名称为"Bearer"和名称为null的情况(因为默认方案可能使用null作为名称):

public class JwtBearerOptionsConfig : IConfigureNamedOptions<JwtBearerOptions>
{
    public void Configure(string name, JwtBearerOptions options)
    {
        // 处理默认的"Bearer"方案,以及未指定名称的情况
        if (name == JwtBearerDefaults.AuthenticationScheme || name == null)
        {
            ConfigureJwtOptions(options);
        }
    }

    public void Configure(JwtBearerOptions options)
    {
        ConfigureJwtOptions(options);
    }

    private void ConfigureJwtOptions(JwtBearerOptions options)
    {
        options.Events.OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];
            var path = context.HttpContext.Request.Path;

            // 匹配SignalR的hub路径,替换成你实际的路径前缀
            if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
            {
                context.Token = accessToken;
            }
            return Task.CompletedTask;
        };
        // 其他JWT配置...
    }
}

2. 明确指定SignalR使用的认证方案

在Startup/Program.cs中配置SignalR时,显式指定使用的认证方案为"Bearer",确保SignalR使用的是你配置过的JwtBearerOptions:

app.MapHub<YourHub>("/hubs/yourhub")
   .RequireAuthorization(options =>
   {
       options.DefaultPolicy = new AuthorizationPolicyBuilder()
           .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
           .RequireAuthenticatedUser()
           .Build();
   });

3. 检查中间件顺序

确保认证中间件在SignalR中间件之前添加:

// 先添加认证中间件
app.UseAuthentication();
app.UseAuthorization();

// 再添加SignalR中间件
app.MapHub<YourHub>("/hubs/yourhub");

为什么SignalR的CONNECT请求会被区别对待?

主要是因为SignalR的CONNECT请求属于HTTP升级请求(比如WebSocket的Upgrade请求),它的管道处理流程和普通的REST API请求略有不同:

  • 这类请求会先被SignalR的中间件识别,提前进入SignalR的处理流程,如果此时认证还没完成,就会直接触发授权质询。
  • 另外,SignalR的请求在某些阶段的上下文传递可能和普通API不同,如果你没有针对性地处理路径,就会导致令牌提取逻辑不生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 16:32:53