HTTP拦截器在发送下一个请求之前不等待令牌刷新

时间:2018-06-27 20:59:17

标签: angular ionic-framework ionic3

我正在使用Ionic 3和Angular5。

我在实现HTTP拦截器时遇到麻烦,如果HTTP拦截器即将过期,它会刷新我的令牌并发送带有新令牌的下一个请求。问题在于它在发出请求之前不等待刷新令牌更新。我该如何解决?

AuthService

refreshToken(token?: string) {
return this.http.get(`${this.API_URL}/refresh`)
  .pipe(catchError(this.handleServerError));
}

TokenInterceptor

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

    // If the next request is to my refresh endpoint allow it through
    if (URL == `${this.globals.APIURL}/refresh`) {
        return request.clone({
                setHeaders: {
                  Authorization: `Bearer ${token}`,
                  'Accept': 'application/json',
                }
              });
    }
    // Else check if token is expiring soon and refresh it and send the new token in the request
    else {
      const expirationLeft = this.authService.getTokenExpiration();
      if (token && expirationLeft < (this.offsetSeconds * 1000) && !this.isUpdating) {
        this.isUpdating = true;
        try {
          this.authService.refreshToken(token)
            .subscribe(data =>
            {
              token = data.token;
              this.authService.storeToken(token);
              this.authService.authenticationNotifier().next(true);
              const clone = request.clone({
                setHeaders: {
                  Authorization: `Bearer ${token}`,
                  'Accept': 'application/json',
                }
              });
              this.isUpdating = false;
              return next.handle(clone);

            },
            (err) =>
            {
              this.authService.logout();
              this.isUpdating = false;
            });
        }
        catch (e) {

        }
    }
    return request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`,
          'Accept': 'application/json',
        }
      });
}

1 个答案:

答案 0 :(得分:1)

此代码应完全重写。因为我不知道代码中实际上需要执行哪些操作,所以无法重写它。但是有几件事可以帮助您。首先从拦截而不是请求返回Observable。

return next.handle(req.clone({
    setHeaders: {
      Authorization: `Bearer ${token}`,
      'Accept': 'application/json',
    }
}));

在其他情况下

this.updating = true;
return this.authService.refreshToken(token).pipe(
       tap(data => {
           this.authService.storeToken(token);
           this.authService.authenticationNotifier().next(true);
           this.isUpdating = false;
       }),
       mergeMap(data => next.handle(req.clone({
           setHeaders: {
               Authorization: `Bearer ${data.token}`,
              'Accept': 'application/json',
           }
       }))),
       catchError(err => {
            this.authService.logout();
            this.isUpdating = false;
            return of('Error');
       })
);

我宁愿将所有refreshToken逻辑移至AuthService。在AuthService中创建一个getToken方法,该方法返回可观察的包装的令牌,并在其中完成有关token和refreshToken的所有操作。在这种情况下,您在拦截器中需要的所有代码都将是

return this.authService.getToken().pipe(
    mergeMap(token=> next.handle(req.clone({
           setHeaders: {
               Authorization: `Bearer ${token}`,
              'Accept': 'application/json',
           }
    })))
);

没有/没有其他条件,没有多次返回。