gpt4 book ai didi

asp.net-core-signalr - signalr 核心 (2.1) JWT 身份验证集线器/协商 401 未经授权

转载 作者:行者123 更新时间:2023-12-02 16:58:08 25 4
gpt4 key购买 nike

所以我有一个 .net core (2.1) API,它使用 JWT token 进行身份验证。我可以成功登录并进行经过身份验证的调用。

我正在为客户端使用 React (16.6.3),它可以获取 JWT 代码并对 API 进行经过身份验证的调用。

我正在尝试将信号中心添加到该站点。如果我不在集线器类上放置 [Authorize] 属性。我可以连接、发送和接收消息(目前它是一个基本的聊天中心)。

当我将 [Authorize] 属性添加到类中时,React 应用程序将向 example.com/hubs/chat/negotiate 发送 HttpPost 。我会收到 401 状态代码。 Authorization: Bearer abc..... header 将被传递。

为了在 React 中构建集线器,我使用:

const hubConn = new signalR.HubConnectionBuilder()
.withUrl(`${baseUrl}/hubs/chat`, { accessTokenFactory: () => jwt })
.configureLogging(signalR.LogLevel.Information)
.build();

其中 jwt 变量是 token 。

我有一些身份验证设置:

services.AddAuthentication(a =>
{
a.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
a.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = false;
options.Audience = jwtAudience;

options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtIssuer,
ValidAudience = jwtAudience,
RequireExpirationTime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtKey)),

};

// We have to hook the OnMessageReceived event in order to
// allow the JWT authentication handler to read the access
// token from the query string when a WebSocket or
// Server-Sent Events request comes in.
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
var authToken = context.Request.Headers["Authorization"].ToString();

var token = !string.IsNullOrEmpty(accessToken) ? accessToken.ToString() : !string.IsNullOrEmpty(authToken) ? authToken.Substring(7) : String.Empty;

var path = context.HttpContext.Request.Path;

// If the request is for our hub...
if (!string.IsNullOrEmpty(token) && path.StartsWithSegments("/hubs"))
{
// Read the token out of the query string
context.Token = token;
}
return Task.CompletedTask;
}
};

});

OnMessageReceived 事件确实被命中,并且 context.Token 确实被设置为 JWT token 。

我无法弄清楚我做错了什么才能对信号器核心进行经过身份验证的调用。

<小时/>

解决方案

我更新了我的代码以使用 2.2(不确定这是否确实需要)。

所以我花了一些时间查看源代码以及其中的示例:

https://github.com/aspnet/AspNetCore

我遇到了 Signalr CORS 问题,已通过以下方式解决:

services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.SetIsOriginAllowed((host) => true) //allow all connections (including Signalr)
);
});

重要的部分是.SetIsOriginAllowed((host) => true)这允许网站和信号器访问的所有连接。

我没有添加

services.AddAuthorization(options =>
{
options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.RequireClaim(ClaimTypes.NameIdentifier);
});
});

我只使用了services.AddAuthentication(a =>

我直接从 github 中的示例中获取了以下内容

            options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];

if (!string.IsNullOrEmpty(accessToken) &&
(context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream"))
{
context.Token = context.Request.Query["access_token"];
}
return Task.CompletedTask;
}
};

不确定属性中是否需要此属性,但在其集线器上使用了它

    [Authorize(JwtBearerDefaults.AuthenticationScheme)]

这样我就无法让多个网站和控制台应用程序通过信号器进行连接和通信。

最佳答案

要与[Authorize]一起使用,您需要设置请求 header 。由于 Web 套接字不支持 header ,因此 token 将与您正确解析的查询字符串一起传递。缺少的一件事是

context.Request.Headers.Add("Authorization", "Bearer " + token);

或者在您的情况下可能context.HttpContext.Request.Headers.Add("Authorization", "Bearer "+ token);

示例:

我就是这样做的。在客户端:

const signalR = new HubConnectionBuilder().withUrl(`${this.hubUrl}?token=${token}`).build();

在服务器上,在 Startup.Configure 中:

app.Use(async (context, next) => await AuthQueryStringToHeader(context, next));
// ...
app.UseSignalR(r => r.MapHub<SignalRHub>("/hubUrl"));

AuthQueryStringToHeader 的实现:

private async Task AuthQueryStringToHeader(HttpContext context, Func<Task> next)
{
var qs = context.Request.QueryString;

if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"]) && qs.HasValue)
{
var token = (from pair in qs.Value.TrimStart('?').Split('&')
where pair.StartsWith("token=")
select pair.Substring(6)).FirstOrDefault();

if (!string.IsNullOrWhiteSpace(token))
{
context.Request.Headers.Add("Authorization", "Bearer " + token);
}
}

await next?.Invoke();
}

关于asp.net-core-signalr - signalr 核心 (2.1) JWT 身份验证集线器/协商 401 未经授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54380097/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com