在刷新JWT令牌后返回重做的调用

时间:2019-05-24 06:55:33

标签: angular rest jwt observable angular-http-interceptors

我正在使用JWT,并且我有以下逻辑:

  1. 拨打http
  2. 如果令牌超出或返回结果,则返回401
  3. 返回401时,我必须进行http调用以要求新令牌
  4. 使用新令牌重新拨打电话
  5. 返回结果

此过程必须对用户隐藏。我已经捕获了401状态代码,并在检索新令牌后重复了原始调用,问题是将结果返回到原始调用。 这是带有http请求的服务:

    getListCategories(){
        return this.http.get<Category[]>("/api/configuration/category").pipe(
          catchError(err =>  this.handleError.handleError(err, { severity: 'error', summary: 'Error retrieving the list of categories', life: 5000 }))
        );
    }

这是进行刷新调用并重复原始调用的错误拦截器:

    export class ErrorInterceptorService implements HttpInterceptor {

      constructor(private auth: AuthService, public router: Router) { }

      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const { shouldRetry } = this;
        return next.handle(request).pipe(
          retryWhen(genericRetryStrategy({
            shouldRetry
          })),

          catchError(err => {
            //401 the token is invalid so I have to refresh it
            if (err.status === 401 && request.url !== "/api/login") {
              this.auth.refreshToken().subscribe(
                (apiResult: SessionTokenResponse) => {
                  this.auth.saveToken(apiResult.token);
                  request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + apiResult.token) });
                  next.handle(request).subscribe();
                },
              );
            } else if (err.status === 401 && request.url === "/api/login") {
              this.auth.logout()
            }else{
              const error = err.error.message || err.statusText;
              return throwError(error);
            }
          }),
        )
      }
      private shouldRetry = (error) => (error.error instanceof ErrorEvent);
    }

问题出在服务中,它不等待remake调用,而是在出现第一个错误后退出。你能帮我吗?谢谢

1 个答案:

答案 0 :(得分:1)

您想通过链式操作返回Observable,该链式操作包括原始请求和重复请求之间的额外请求。我会尝试使用switchMap来做到这一点。

会是这样的:

catchError(err => {
            if (err.status === 401 && request.url !== "/api/login") {
              //by returning observable here, you are "chaining" the calls so original caller will get this observable's result. `catchError` can be threated like `catch` block in `try-catch` where you can still do operations and return results - ergo continue operations.
              return this.auth.refreshToken()
                .switchMap( // this just switches from one observable to another
                (apiResult: SessionTokenResponse) => {
                  this.auth.saveToken(apiResult.token);
                  request = request.clone({ headers: request.headers.set('Authorization', 'Bearer ' + apiResult.token) });
                  return next.handle(request); // return original request handler with updated headers
                },
              );

显然未经测试,语法可能无效,如此处所述。