在授权 Web 套接字之前追加授权 Header

Append Authorization Header Before Authorizing Web Sockets

我正在重构我的 API 以使用内置的 .Net 身份验证而不是 IdentityServer4

在我的旧代码中,我会将身份验证令牌附加到 websocket 地址并使用中间件

注入 header
public class SignalRQueryStringAuthMiddleware
{
    private readonly RequestDelegate _next;

    public SignalRQueryStringAuthMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Convert incomming qs auth token to a Authorization header so the rest of the chain
    // can authorize the request correctly
    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Query.TryGetValue("A5S0kT0k", out var token))
        {
            context.Request.Headers.Add("Authorization", "Bearer " + token.First());
        }
         await _next.Invoke(context);
    }
}

我可以看到我的中间件正在按预期执行并附加了正确的授权 Header。

然而,在我的启动过程中,我的授权似乎从未被调用,它直接移动到连接到 websocket'

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(cfg => {
        cfg.RequireHttpsMetadata = false;
        cfg.SaveToken = true;

        cfg.Events = new JwtBearerEvents
        {
            OnMessageReceived = async (ctx) =>
            {
                Console.WriteLine(ctx.Token);
            },

            OnTokenValidated = async (ctx) =>
            {
                Console.WriteLine("BreakPoint");
            },

            OnAuthenticationFailed = async (ctx) =>
            {
                Console.WriteLine("Breakpoint");
            }
        };

        cfg.TokenValidationParameters = tokenValidationParameters;
    });

这是我的管道在配置中的执行顺序

app.UseSignalRQueryStringAuth();

app.UseAuthentication();

app.UseSignalR(routes =>
{
    routes.MapHub<DefaultServiceHubBase<MessageDTO>>("/messages");
    routes.MapHub<DefaultServiceHubBase<ConversationDTO>>("/conversations");
    routes.MapHub<InMemoryHub<UserLocationDTO>>("/user-locations");
});

我配置我的管道,以便首先命中中间件,但我永远无法命中 JWTBearer 部分中的任何断点的身份验证,但是,如果我制作标准的 HttpRequest,一切正常吗?

我的 OnMessageReceived 被忽略了,它直接转到我中心的 onconnect 函数 为什么会这样?

不知道为什么,但事实证明我还需要添加一个默认的挑战模式

services.AddAuthentication(options =>
{
    // Identity made Cookie authentication the default.
    // However, we want JWT Bearer Auth to be the default.
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})

我在 Signalr Authentication Docs

中找到了这个