【问题标题】:HTTP Interceptor not waiting for token to be refreshed before sending next requestHTTP拦截器在发送下一个请求之前不等待刷新令牌
【发布时间】:2018-06-27 20:59:17
【问题描述】:

我正在使用 Ionic 3 和 Angular 5。

我在实现一个 HTTP 拦截器时遇到问题,该拦截器会在我的令牌即将到期时刷新它并使用新令牌发送下一个请求。问题是它在发出请求之前没有等待刷新令牌更新。我该如何解决这个问题?

身份验证服务

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

令牌拦截器

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',
        }
      });
}

【问题讨论】:

    标签: angular ionic-framework ionic3


    【解决方案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 方法,该方法返回由 observable 包装的令牌,并在那里实现有关令牌和 refreshToken 的所有内容。拦截器将是干净的,只是做它的工作 - 拦截。在这种情况下,您在拦截器中需要的所有代码都将是

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

    没有 if/else 条件,没有多重返回。

    【讨论】:

    • 如果我将代码移动到getToken(),如何在拦截器中返回令牌?
    • 这不起作用我收到此错误An error occurred TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    • 看最后一个例子,token是mergeMap的参数,所以你总是可以访问它。
    • 你知道这是否可以防止突发,比如 3 个请求同时发出,并且所有三个请求都需要身份验证令牌?这是否会导致三个令牌刷新,因为每个令牌都确定它需要刷新?或者,拦截器是否会阻塞其他两个请求,直到调用 next.handle()?
    • 不,在这个实现中没有阻塞。但是考虑到它只是一个线程,那么这意味着不可能同时发出 3 个请求,它们应该是随之而来的。因此,当调用refreshToken 而不是立即发送请求并返回它时,如果已发送刷新令牌的请求,您可以检查一些标志或其他内容。如果是,则只需返回等待结果的可观察对象,而不是创建新请求.
    猜你喜欢
    • 1970-01-01
    • 2014-12-20
    • 2023-03-16
    • 2020-01-13
    • 1970-01-01
    • 2017-12-31
    • 2018-06-12
    • 2017-12-25
    • 1970-01-01
    相关资源
    最近更新 更多