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

WPF连接SignalR时Identity始终为空,API请求则正常,求排查

问题描述

开发了一个WPF应用用于连接SignalR API,遇到Identity相关问题:调用常规API端点(GET、POST、PUT、DELETE)时,Identity能正确填充所有声明;但连接SignalR时,Identity Claims却不存在。

后端JWT注册代码

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => {
            options.TokenValidationParameters = new TokenValidationParameters {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = configuration["Jwt:Issuer"],
                ValidAudience = configuration["Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
            };
            options.Authority = configuration["Jwt:Authority"];
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;
            options.Events = new JwtBearerEvents()
            {
                
                OnMessageReceived = context =>
                {
                    var accessToken = context.Request.Query["access_token"];
                    // If the request is for our hub...
                    var path = context.HttpContext.Request.Path;
                    if (!string.IsNullOrEmpty(accessToken) &&
                        (path.StartsWithSegments("/hubs")))
                    {
                        // Read the token out of the query string
                        context.Token = accessToken;
                    }

                    return Task.CompletedTask;
                },
            };
    });

WPF端SignalR连接代码

_connection = new HubConnectionBuilder()
        .ConfigureLogging(logBuilder =>
        {
            logBuilder.AddConsole();
            logBuilder.AddDebug();
        })
        .WithUrl($"{url}/hubs", options =>
        {
            options.AccessTokenProvider = _userService.GetToken;//returns Task.FromResult(userToken)
        })
        .WithAutomaticReconnect(new[]
        {
            TimeSpan.Zero,
            TimeSpan.FromSeconds(2),
            TimeSpan.FromSeconds(10),
            TimeSpan.FromSeconds(30),
            TimeSpan.FromSeconds(60),
            TimeSpan.FromSeconds(120)
        })
        .Build();

JWT配置

"jwt":{
    "Key":"some random generated key",
    "Issuer":"https://localhost:5001/",
    "Audience":"https://localhost:5001/",
    "Authority":"https://localhost:5001/"
  },
排查与修复方案

1. 移除冲突的JWT验证配置

你同时配置了TokenValidationParameters和Authority,这会导致验证逻辑冲突:

  • 指定Authority后,系统会启用OpenID Connect发现机制,忽略手动设置的签发者、受众和签名密钥
  • 你的JWT是用自定义对称密钥生成的,并非来自Authority指向的身份提供者,因此验证失败,Claims无法填充

修复操作:
删除options.Authority = configuration["Jwt:Authority"];这一行,保留手动配置的TokenValidationParameters即可,修改后的后端代码如下:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options => {
            options.TokenValidationParameters = new TokenValidationParameters {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = configuration["Jwt:Issuer"],
                ValidAudience = configuration["Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
            };
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;
            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("/hubs"))
                    {
                        context.Token = accessToken;
                    }
                    return Task.CompletedTask;
                },
            };
    });

2. 确认客户端Token有效性

检查_userService.GetToken返回的JWT是否有效:

  • 用JWT解析工具验证Token包含所需的Claims
  • 确认Token的签发者、受众与后端配置完全一致
  • 确保Token未过期

3. 给Hub添加授权特性

如果你的SignalR Hub类没有添加[Authorize]特性,即使Token验证通过,Identity也不会被填充,需补充该特性:

[Authorize]
public class YourHub : Hub
{
    // Hub业务方法
}

4. 查看验证日志排查问题

在后端开启详细日志,定位JWT验证失败的具体原因:
在appsettings.json中添加日志配置:

"Logging": {
    "LogLevel": {
        "Microsoft.AspNetCore.Authentication": "Debug",
        "Microsoft.AspNetCore.SignalR": "Debug"
    }
}

启动项目后查看日志,可获取Token验证过程中的错误信息(如签名不匹配、签发者错误等)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 17:55:18