【问题标题】:Refresh token in Angular 4 for multiple api calls在Angular 4中刷新令牌以进行多个api调用
【发布时间】:2018-03-14 07:25:16
【问题描述】:

我正在尝试在我的网络应用中实现刷新令牌概念。

在页面刷新中,我调用了 4 个 API,当访问令牌过期时,我调用后端以获取基于刷新令牌的新访问令牌。

因此,在我的情况下,我能够获得新的访问令牌,但再次无法触发 4 个 API 调用,除非手动刷新页面或从服务重新加载页面。但我不想重新加载页面并希望在不知道最终用户的情况下完成 API 调用。

提出一些建议或想法。

【问题讨论】:

  • 您可以在令牌更新调用的subcsribe 中调用服务。如果您可以共享代码示例,很容易提出建议。
  • 你有一些代码说明你现在所做的事情吗?

标签: angular access-token angular-services


【解决方案1】:

您可以使用 Angular HttpInterceptor 来解决您的问题。请参阅下面的 sn-p。

@Injectable()
export class KgRequestInterceptorService implements HttpInterceptor {
  authenticationService: MyAuthenticationService;
  snackbarService: KgSnackbarService

  constructor(private injector: Injector) { }

  addBearerAndHeaders(req: HttpRequest<any>, token: string, overwrite?: boolean): HttpRequest<any> {
    reqHeaders = reqHeaders.set("Authorization", 'Bearer ' + token);
    return req.clone({ headers: reqHeaders });
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    this.authenticationService = this.authenticationService ? this.authenticationService : this.injector.get<MyAuthenticationService>(MyAuthenticationService);
    return next.handle(this.addBearerAndHeaders(req, this.authenticationService.accessToken)).pipe(
      catchError((error, cought) => {
        if (error instanceof HttpErrorResponse) {
          switch ((<HttpErrorResponse>error).status) {
            case 400:
              return this.handle400Error(error);
            case 401:
              return this.handle401Error(req, next);
            case 403:
              return this.handle403Error(error);
            default:
              return _throw(error);
          }
        } else {
          return _throw(error);
        }
      })

    )
  }

  handle401Error(req: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshingToken) {
      this.tokenSubject.next(null);
      this.isRefreshingToken = true;
      console.log("isRefreshingToken", this.isRefreshingToken);


      // Reset here so that the following requests wait until the token
      // comes back from the refreshToken call.
      this.authenticationService = this.authenticationService ? this.authenticationService : this.injector.get<KgAuthenticationService>(KgAuthenticationService);
      this._location = this._location ? this._location : this.injector.get<Location>(Location);

      return this.authenticationService.renewToken().pipe(
        switchMap((newToken: string) => {
          if (newToken) {
            console.log("newToken Recieved:", newToken);

            this.tokenSubject.next(newToken);
            this.authenticationService.storeRenewedToken(newToken);
            return next.handle(this.addBearerAndHeaders(req, newToken, true));
          }

          // If we don't get a new token, we are in trouble so logout.
          //return this.logout();
        }),
        catchError(error => {
          // If there is an exception calling 'refreshToken', bad news so logout.
          //return this.logout();
        }),
        finalize(() => {
          this.isRefreshingToken = false;
          console.log("isRefreshingToken", this.isRefreshingToken);
        })
      );
    } else {
      return this.tokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(token => {
          console.log("newtoken:", token.substr(token.length - 20, token.length - 1))
          return next.handle(this.addBearerAndHeaders(req, token, true));
        })
      )
    }
  }

  handle400Error(error) {
    if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
      // If we get a 400 and the error message is 'invalid_grant', the token is no longer valid so logout.
      return this.logoutUser();
    }

    return _throw(error);
  }

  handle403Error(error) {
    if (error.status === 403) { }
    return _throw(error);
  }
}

关于这方面的好文章在https://www.intertech.com/Blog/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/

【讨论】:

  • 如果在刷新令牌后有多个请求要处理,这将不起作用。刷新token后,只处理一个请求,其他请求不处理。
  • @RishabhShah 多亏了 tokenSubject,它才能工作。第一个请求将启动刷新过程,所有下一个请求将等待令牌可用:this.tokenSubject.pipe(filter(token => token != null), take(1)....
  • 这似乎不起作用,renewToken 似乎永远不会执行。
【解决方案2】:

在这种情况下,最好使用 switchMap 当你有一个 Observable 并且你需要从另一个请求中获取一些东西并返回一个不同的 Observable 时,你可以使用 SwitchMap: https://blog.angular-university.io/rxjs-switchmap-operator/

ngOnInit() {
    this._moviesDataService.getShowtimes()
        .switchMap(res => { 
            const id = Object.keys(res[0].showtimes)[0]; // assuming you have one element in your array and you want the first id from showtimes
            return this.getMovies(id); // assuming, you have a separate method that returns the movies
        })
        .subscribe(res => this.results = res)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-06
    • 2021-09-01
    • 2021-03-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 2018-05-27
    • 2019-11-26
    相关资源
    最近更新 更多