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

.NET Core 8中SignalR+OpenIddict认证连接异常求助

.NET Core 8 + OpenIddict + SignalR 连接故障排查

问题概述

  • 基于.NET Core 8搭建集成OpenIddict认证的SignalR服务器,客户端连接持续失败
  • Flutter使用signalr_netcore包连接时,触发WebSocket升级失败、握手未完成错误
  • Postman测试WebSocket请求:URL带id参数返回400错误,不带则返回200;请求体固定为{"protocol":"json","version":1}
  • 服务器仅输出OpenIddict认证成功日志,无任何SignalR相关日志
  • 已尝试多套网上解决方案及多个Flutter SignalR插件,均未解决问题
  • 服务器与Flutter应用均在本地环境运行

服务器代码

Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR(options =>
{
    options.EnableDetailedErrors = true;
    options.DisableImplicitFromServicesParameters = true;
});
builder.Services.AddSingleton<IUserIdProvider, UserIdProvider>();

builder.Services.AddOpenIddict()
    .AddValidation(builder =>
    {
        builder.SetIssuer("<my-auth-url>");
        builder.AddAudiences("<my-client-id>");
        builder.UseIntrospection()
               .SetClientId("<my-client-id>")
               .SetClientSecret("<my-secret>");

        builder.UseSystemNetHttp();
        builder.UseAspNetCore();
    });

builder.Services.AddAuthentication(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
builder.Services.AddAuthorization();

builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>());

var app = builder.Build();

app.UseHttpsRedirection();

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

app.MapControllers();

app.MapHub<ChatHub>("chat");

app.Run();

ChatHub代码

[Authorize]
public class ChatHub(
    ILogger<ChatHub> logger) : Hub<IChatClient>
{
    public async Task SendMessage(string message)
    {
        await Clients.All.ReceiveMessage(Context.UserIdentifier, message);
    }
}

排查与解决方案

1. 强化认证中间件配置

当前AddAuthentication未显式指定默认认证/挑战Scheme,可能导致SignalR无法正确触发OpenIddict认证,修改配置:

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});

2. 启用SignalR详细日志

在appsettings.json中添加日志配置,获取SignalR握手、连接的详细错误信息:

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

3. 修复WebSocket请求的id参数问题

SignalR WebSocket握手请求中id为必填参数,需满足:

  • 参数值为GUID格式字符串(如?id=123e4567-e89b-12d3-a456-426614174000)
  • 请求头必须携带有效的Bearer令牌(OpenIddict颁发的认证令牌)
  • Postman测试时需确保请求方法为POST,请求体Content-Type设为application/json

4. 校验OpenIddict Introspection配置

  • 确认<my-auth-url>为本地认证服务器的正确地址(如https://localhost:5001)
  • 认证服务器需启用Introspection端点,且客户端ID/密钥与服务器配置完全匹配
  • 确保请求令牌包含SignalR所需的scope(如signalr),且认证服务器允许该客户端执行令牌 introspection

5. Flutter客户端配置修正

  • 升级signalr_netcore到最新稳定版,确保与.NET Core 8兼容
  • 显式指定WebSocket传输方式并添加认证头:
    final connection = HubConnectionBuilder()
      .withUrl('https://localhost:xxxx/chat', 
        HttpConnectionOptions(
          headers: {
            'Authorization': 'Bearer ${yourAuthToken}'
          },
          transport: HttpTransportType.webSockets,
        ))
      .build();
    
  • 先禁用自动重连,确保单次连接逻辑正确后再启用

6. 添加跨域配置(本地跨端口场景)

若Flutter与服务器运行在不同端口,需配置CORS允许SignalR跨域:

builder.Services.AddCors(options =>
{
    options.AddPolicy("SignalRCors", policy =>
    {
        policy.WithOrigins("http://localhost:xxxx") // Flutter本地运行地址
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials();
    });
});

// 在UseAuthentication前注入CORS中间件
app.UseCors("SignalRCors");

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:12:46