在Angular拦截器类中调用异步函数

时间:2019-08-09 02:45:45

标签: angular rxjs amazon-cognito interceptor

我正在使用AWS Cognito对Angular应用程序中的用户进行身份验证。我想在每个小时到期之前自动刷新会话。

我们使用Angular拦截器类在每个请求的标头中设置访问令牌。用户登录后,时间将保存并存储在本地存储中。在每个HTTP请求之前都会对此进行检查,如果周期大于一小时,请从amazon-cognito-identity-js库调用cognito用户池refreshSession函数。

但是,这种方法似乎无法无缝刷新会话。我已经能够刷新会话,但是进行的调用返回401,只有在此之后,会话才会被刷新。

拦截器如下:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const invalid = this.checkSessionNotValidViaStorage();
    if (invalid) {
      return from(this.authenticationService.refreshSessioFromPromise()).pipe(result => {
        const newRequest = this.setHeader(request);
        return next.handle(newRequest);
      });
    } else {
      const newRequest = this.setHeader(request);
      return next.handle(newRequest);
    }
}

身份验证服务如下:

refreshSessioFromPromise(): Observable<string> {
    return from((resolve: any, reject: any) => {
      const currentUser = this.getCurrentUser();
      currentUser.getSession((getSessionErr: any, getSessionSession: any) => {
        const refreshToken = getSessionSession.getRefreshToken();
        currentUser.refreshSession(refreshToken, (refreshSessionErr, refreshSessionSession) => {
          if (refreshSessionErr) {
            reject('Cognito: Can not set the credentials:' + refreshSessionErr);
          } else {
            this.setCredentials(refreshSessionSession, this.remember);
            this._credentials = refreshSessionSession;
            resolve('Cognito: refreshed successfully');
          }
        });
      });
    });
}

这种使用RxJs from函数的方法基于the article by Michael Karén Michael Karén

我也尝试过使用promise和其他RxJs方法。好像amazon-cognito-identity-js lib正在丢弃异步球,因此,最大的问题是如何确保在允许任何更多调用继续之前刷新会话。

可能使用拦截器不是正确的方法,并且在HTTP服务之上需要有另一层来实现此目的。

对于使用适当的RxJs / Angular拦截器方法进行此操作的任何帮助,或者其他更好的方法,将不胜感激。

1 个答案:

答案 0 :(得分:0)

错误在于拦截功能。像这样重构它:

from(this.authenticationService.refreshSessioFromPromise()).pipe(
  switchMap(result => {
    const newRequest = this.setHeader(request);
    return next.handle(newRequest);
  })
)

管道函数需要RxJS运算符。在这种情况下,我们应该获取auth服务的observable返回的值,并切换到next.handle调用返回的observable。

因为我们要从一个可观察的对象转到另一个可观察的对象,所以我们需要使用扁平化运算符。转换为可观察值的承诺会发出一个值,然后完成。这意味着我们不必担心扁平化策略,使用简单的switchMap就可以了。如果您对其他扁平化策略感到好奇,请查看concatMapexhaustMapmergeMap运算符,