【问题标题】:Return remaked call after JWT token refreshJWT 令牌刷新后返回重新调用
【发布时间】:2019-10-10 17:48:14
【问题描述】:

我正在使用 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);
    }

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

【问题讨论】:

  • 为什么要等待?你的 refreshToken() 是异步的
  • 对,但怎么能强迫它等待呢?

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


【解决方案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
                },
              );

显然没有经过测试,可能是此处所写的语法无效。

【讨论】:

  • 我将 switchMap 放在管道中,它似乎可以工作,我正在测试它。谢谢
猜你喜欢
  • 2020-12-26
  • 2021-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-12
  • 2016-03-05
  • 2016-06-25
  • 2016-01-05
相关资源
最近更新 更多