跨选项卡计划访问令牌刷新

Joe*_*oel 5 javascript angular

为了对我的Angular应用程序中的用户进行身份验证,我使用有效期为X秒的访问令牌,并刷新可用于将身份验证再延长X秒的令牌。

所以流程是这样的:

  • 用户登录。访问令牌和刷新令牌都存储在本地存储中
  • 设置了计时器(比X秒短5%)。
  • 计时器完成后,刷新令牌请求将发送到服务器,并使用结果(新的)访问和刷新令牌更新本地存储。

我的问题是这样的:

  • 如果打开了多个选项卡,将不可避免地遇到同时从多个选项卡触发刷新的情况。服务器将接受第一个请求,但会400 Bad Request - Invalid refresh token为后续请求抛出,因为它认为已使用它们。

有谁知道如何解决这个问题?如何跨选项卡/窗口同步内容?我有两个想法,但似乎都有些牵强:

  • 如果响应为400 Bad Request,则请稍后重试(或检查是否已存在有效的更新令牌)。
  • 尝试通过在选项卡之间发布消息来跨选项卡同步服务器请求。

小智 3

不要设置计时器,添加拦截器并捕获错误,如果出现 401 错误,请执行刷新令牌流程,然后使用新令牌重复失败的请求

intercept(request: HttpRequest<any>, next: HttpHandler): 
        Observable<HttpEvent<any>> {

return next.handle(request).pipe(
  catchError((error: HttpErrorResponse) => {
    if (error.status == 401) {
      return this.refreshToken(request, next);
     } 
    }
    return throwError(error);
  })
);


      private refreshingInProgress: boolean = false;
  private accessTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  private refreshToken(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!this.refreshingInProgress) {
      this.refreshingInProgress = true;
      this.accessTokenSubject.next(null);
      return this.authenticationService.refreshToken().pipe(
        switchMap((res: any) => {
          this.refreshingInProgress = false;
          this.accessTokenSubject.next(res);
          // repeat failed request with new token
          return next.handle(this.addToken(request, res));
        })
      );
    } else {
      // wait while getting new token
      return this.accessTokenSubject.pipe(
        filter((token) => token !== null),
        take(1),
        switchMap((token) => {
          // repeat failed request with new token
          return next.handle(this.addToken(request, token));
        })
      );
    }
  }
  
  private addToken(request: HttpRequest<any>, token: Credentials) {
    return request.clone({
      setHeaders: {
        Authorization: `Bearer ${token.access_token}`,
      },
    });
  }
Run Code Online (Sandbox Code Playgroud)