在信号器集线器类上设置 [Authorize] 属性仅在连接到集线器时有效,而不是在集线器上的每个方法之前(ASP.NET Core 2.2)
Posted
技术标签:
【中文标题】在信号器集线器类上设置 [Authorize] 属性仅在连接到集线器时有效,而不是在集线器上的每个方法之前(ASP.NET Core 2.2)【英文标题】:Setting [Authorize] attribute on signalr hub class works only when connecting to the hub and not before each method on the hub (ASP.NET Core 2.2) 【发布时间】:2022-01-16 08:08:41 【问题描述】:我正在尝试向我的 signalR 集线器添加身份验证,但它仅适用于“协商”方法,而不适用于发送到集线器的每个请求。
在Startup.cs
下ConfigureService
我添加了:
// Authentication
services.AddAuthentication(options =>
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
)
.AddJwtBearer(options =>
options.TokenValidationParameters = GetTokenValidationParameters(authSettings.PublicKey);
options.IncludeErrorDetails = 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;
,
;
);
在我添加的Configure
方法中:
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/hubs"), config => config.UseAuthentication());
并在 hub 类上添加了[Authorize]
属性:
[Authorize]
public class ProtocolMethodsHub : Hub<IProtocolMethodsHub>, IProtocolMethodsHub
我在OnMessageReceived
中设置了一个断点,但它仅在连接到 signalR 时调用,而不是针对通过 websocket 发送的每个请求。
有没有办法对中心的每个请求进行身份验证/授权?
【问题讨论】:
【参考方案1】:SignalR 在后台使用different transports,每种传输方式的行为可能略有不同。例如,如果它使用 Websocket 传输,您正在服务器和客户端之间创建一个持久连接,并且所有请求都通过此连接(这与普通 HTTP 请求不同),因此它仅在建立期间检查 JWT 有效性的连接。对于其他传输,检查发生得更频繁,但它们仍然仅在您建立与服务器的客户端连接时发生。换句话说,您已经检查了 JWT,并且您知道在请求开始进入时它是有效的,并且 SignalR 不会仔细检查 JWT。如果您想控制 JWT 的授权和访问,您可能需要:
-
使用具有不同访问级别的不同集线器。
在 SignalR 集线器中检查令牌的声明,以查看用户是否有权访问他们正在执行的操作。
更新:所以在阅读了 cmets 之后,我意识到您正在寻找当 JWT 过期但连接仍处于活动状态时该怎么办。这只是 Websocket 传输的问题,因为它保持持久连接。我不相信有一种内置的方法来处理这个问题,所以我可以想到两种不同的方法:
-
创建 JWT 时,在 JWT 中包含时间戳声明,以便每次 SignalR 集线器中有请求时都可以访问它,如果时间戳过期,只需关闭连接并强制连接创建新 JWT (假设您的客户端中有重新连接逻辑)。使用这种方法,除了时间戳之外,您还可以进行更复杂的检查,以确保 JWT 仍然有效。
在您的客户端代码中有一个计划,每隔几分钟自动关闭和重新打开连接。如果您试图尽量减少连接中断的时间,这可能会导致问题。
【讨论】:
感谢您的详细回复。我们使用 WebSockets,但是我们如何在会话期间处理过期的令牌? 处理实际的 JWT 将取决于您的客户端。如果您使用的是 .NET 客户端,则需要执行以下操作:new HubConnectionBuilder().WithUrl(hubUrl, connectionOptions => connectionOptions.AccessTokenProvider = // Your access token provider ).Build();
在客户端上处理 JWT 的检索、存储和生成。
重新阅读您的评论后,我想我可能知道您在问什么。您是否在问当 JWT 过期但连接仍处于活动状态时该怎么办?基本上如何中断连接并要求客户端获取新的JWT?
没错。你知道怎么做吗?
@user1977367 我更新了答案,因为它不适合这里。希望对您有所帮助。【参考方案2】:
这样按请求添加/删除中间件感觉不对:
app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/hubs"), config => config.UseAuthentication());
您可以在系统的授权部分更好地处理它。 AddJwtBearer 不关心传入请求是否包含令牌。就是这样,如果 thr 请求包含一个令牌,那么它应该是有效的。 AddJwtBearer 确实关心您可以做什么,该工作是授权部分。 AddJwtBearer 想要做的就是根据传入的令牌创建一个 User 对象。
【讨论】:
以上是关于在信号器集线器类上设置 [Authorize] 属性仅在连接到集线器时有效,而不是在集线器上的每个方法之前(ASP.NET Core 2.2)的主要内容,如果未能解决你的问题,请参考以下文章