【问题标题】:renew token in signalR after expired token令牌过期后在 signalR 中更新令牌
【发布时间】:2020-09-21 21:56:30
【问题描述】:

我通过 SignalR 从客户端(角度 9)和服务器(asp.net core 3.1)创建实时连接,并通过 JWT 令牌授权集线器,例如以下代码:

 private createConnection() {
      this.hubConnection = new HubConnectionBuilder().withUrl(`${this.appConfig.hubEndpoint}/Hubs`,
        { accessTokenFactory: () => jwtToken })
        .withAutomaticReconnect()
        .build();
  }

  private startConnection(): void {
    this.hubConnection
      .start()
      .then(() => {
        this.connectionIsEstablished = true;
        this.connectionEstablished.emit(true);
      })
      .catch(err => {
        console.log('Error while establishing connection, retrying...');
      });
  }

在令牌过期之前,这可以正常工作。根据我的研究,在收到带有刷新令牌的新令牌后,应该停止之前的连接,并应该使用新令牌创建新连接。 现在我想知道我该怎么做?我必须经常检查令牌吗?还是应该通过向服务器发送每个请求来解决这个问题?

【问题讨论】:

  • 你找到方法了吗?
  • @Kardon63 你也找到方法了吗? xD
  • @MehdiBenmoha 在关闭事件中,您可以检查错误字符串是否包含unauthorized,然后您可以重新启动连接,但尚未实现,但我认为应该这样做
  • 我正在试一试..如果我能正常工作会更新你
  • @Kardon63 onclose 事件被触发,但字符串不包含未授权,监听器获得undefined 值。我也很难更新连接,因为我正在使用异步调用来获取令牌,并且我正在用 rxJS 包装整个系统,所以快速而肮脏的修复是在收到断开连接的事件时重新加载页面,同时还为自动重新连接设置了激进的延迟。

标签: angular asp.net-core signalr refresh-token


【解决方案1】:

当令牌过期时,服务器将断开连接,您将在服务器端遇到错误。我相信你会得到 405 错误代码Method now allowed

因此,您需要捕获此令牌过期错误并断开连接,以便您可以使用新令牌启动新的连接。

【讨论】:

  • 令牌过期时没有收到错误消息。执行集线器的方法时发生错误。能否介绍一下该领域实现的文章或示例?
  • 您有令牌到期时间,假设您为令牌定义 1 小时,然后在您的集线器上使用 ConnectionTimeout 定义连接仅对 1 小时有效。
  • @Kiril1512 我可以在重新连接事件中刷新令牌,还是我需要强制创建新的连接,你能举个例子吗?
  • @Kardon63 对不起,我不知道你是否可以在重新连接时这样做
【解决方案2】:

什么对我有用,这是一个快速而肮脏的修复,是在关闭事件时重新加载页面:

this.hubConnection.onclose(() =>{
  window.location.reload()
})

说明

我正在使用 RxJS 包装连接过程,因此对我的情况更好的解决方法是抛出错误而不是重新加载页面并使用 retryWhen 运算符捕获它。但由于这是一个硬错误(需要等待 1 小时让令牌过期,并且本地模拟器不关心令牌......),我只是更喜欢使用这个临时解决方案。

【讨论】:

    【解决方案3】:

    我想出的解决方案是通过扩展它使用的signalR.DefaultHttpClient 来拦截signalR 客户端的auth 调用。如果有 401,那么我刷新令牌(通过我的 authService),然后重试调用:

    打字稿:

    const getAuthHeaders = () => {
      return {
        Authorization: `Bearer ${authService.getToken()?.accessToken}`,
      };
    };
    
    class CustomHttpClient extends signalR.DefaultHttpClient {
      constructor() {
        super(console); // the base class wants a signalR.ILogger
      }
      public async send(
        request: signalR.HttpRequest
      ): Promise<signalR.HttpResponse> {
        const authHeaders = getAuthHeaders();
        request.headers = { ...request.headers, ...authHeaders };
    
        try {
          const response = await super.send(request);
          return response;
        } catch (er) {
          if (er instanceof signalR.HttpError) {
            const error = er as signalR.HttpError;
            if (error.statusCode == 401) {
              //token expired - trying a refresh via refresh token
              await authService.refresh();
              const authHeaders = getAuthHeaders();
              request.headers = { ...request.headers, ...authHeaders };
            }
          } else {
            throw er;
          }
        }
        //re try the request
        return super.send(request);
      }
    }
    
    const connection = new signalR.HubConnectionBuilder()
      .withUrl("/MyHub", {
    // use the custom client
        httpClient: new CustomHttpClient(),
      })
      .configureLogging(signalR.LogLevel.Information)
      .build();
    

    在此处查看.withUrl(..) 的选项:https://docs.microsoft.com/en-us/aspnet/core/signalr/configuration?view=aspnetcore-6.0&tabs=dotnet

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-05
      • 2019-05-31
      • 2020-04-01
      • 1970-01-01
      • 2021-05-09
      • 1970-01-01
      • 2018-02-10
      • 2021-12-19
      相关资源
      最近更新 更多