有没有办法断开用户与 Signalr 服务器端的连接?

Is there a way to disconnect user from Signlar server side?

我正在构建一个使用 SignalR 传输实时消息的应用程序,我正在徘徊是否有任何方法可以让我在服务器端断开用户连接。

由于 SignalR 处理身份验证的方式,我想断开它们。 Signalr 似乎不检查令牌是否在打开的 websocket 连接内过期(它仅在请求开始时或客户端发送消息时检查)。

另一个解决方案是在给定时间后断开客户端。

目前,我所拥有的用于身份验证的只是在 accessTokenProvider 内部发送的 JWT 令牌。

客户端:

 new HubConnectionBuilder()
      .withUrl(`${env.APPURL}/hub`, {
        skipNegotiation: true,
        transport: HttpTransportType.WebSockets,
        accessTokenFactory: async () => {
          const { token } = store;

          return token;
        },
      })

我在客户端处理这个问题。我的 angular 应用程序使用静默刷新令牌调用来刷新 jwt 令牌并保持用户身份验证。

当我将 SignalR 功能添加到我的应用程序时,我还需要更新活动 SignalR 连接的访问​​令牌。 经过一些研究,唯一的方法是 'reset' 连接。当您停止并再次启动连接时,SignalR 将使用您通过访问令牌工厂传递给它的最新令牌。

如果你想做这个服务器端,你可以向所有客户端发送一条消息,客户端停止连接并立即重新启动它。

最终,停止连接的代码必须在客户端完成。

-- 更新 --

ASP.NET Core SignalR 在 Hub class 中有 Abort 方法。 (但是在 ASP.NET SignalR 中无法执行此操作。

使用此 Abort 方法,您可以 运行 以每个连接为基础的逻辑,如果需要停止连接,则:

    public void AuthenticateConnection()
    {
        // Run your logic to determine if connection needs to be stopped

        // If connection must be stopped
        Context.Abort();
    }

尽管这确实会停止连接,但无法提供重新启动它的方法,因此您会陷入客户端永久断开连接的状态。因此,如果您打算更新客户端不记名令牌,那么我不确定这是否适合您。

对于更新 JWT 不记名令牌的用例,我建议在您获取令牌时在客户端设置一个 'refresh-token' 计时器。

如果我登录并且令牌从现在起 15 分钟后过期,我将设置一个 14 分钟的计时器,之后我将刷新令牌以保持用户登录状态。每次成功刷新令牌时,我都会停止并启动连接(传递更新的令牌)。

如果您必须从服务器端执行此操作,一种解决方案是发送断开连接消息和客户端 ID,然后具有该 ID 的客户端将收到消息:

服务器端

Clients.All.SendAsync($"disconnect-{clientId}");

客户端

this.connection.on(
  `disconnect-${this.clientId}`, async () => {
    await this.connection.stop();
    await this.connectionstart();
  }
);