在服务器响应 401 错误后使用拦截器附加正确的令牌

Using interceptor to attach the correct token after server responds with an 401 error

我正在尝试为所有身份验证问题创建一个错误处理方法。我 运行 遇到一个问题,我的 authTokenService.getAmadeusAuthToken$ 方法正在被调用,但由于它是一个 post 调用,return 是一个新令牌,因此需要更长的时间来解决,在同时,在检索令牌之前,catchError obvservable returns next.handle。我尝试了几种不同的方法,但我不知道让拦截器方法等待 authTokenService.getAmadeusAuthToken$ 完成的最佳方法。这是我的代码:

My Interceptor:

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    return next.handle(req).pipe(
      catchError((response: HttpErrorResponse) => {
        return next.handle(req).pipe(
          tap(test => {
            this.authTokenService.getAmadeusAuthToken$().pipe(
            ).subscribe(token => {
            const authReq = req.clone({
              headers: req.headers.append('Authorization', 'Bearer ' + token.access_token)
            });
            return next.handle(authReq);
            })
          })
        )
      })

post调用获取新令牌的方法

  getAmadeusAuthToken$():  Observable<any>{
const httpOptions = {  headers: new HttpHeaders().set('Content-Type', "application/x-www-form-urlencoded")}
return this.http.post<Token>('https://test.api.amadeus.com/v1/security/oauth2/token', this.body, httpOptions)

}

为了确保拦截方法有效,我进行了一次 API 调用以仅获取新令牌并将其硬编码进去。拦截方法非常有效,因为没有竞争条件,并且拦截器 return 立即使用令牌 next.handle()。

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    return next.handle(req).pipe(
      catchError((response: HttpErrorResponse) => {
         const authReq = req.clone({
              headers: req.headers.append('Authorization', 'Bearer ' + "lkVkfilWizfcuyVpXBQsA08XkUy5")
            });
        return next.handle(authReq);
      })

所以基本上我想确保拦截器等待 authTokenService.getAmadeusAuthToken$ 完成获取令牌,然后 return 新的 next.handle 和令牌,什么是我这里不见了?

而不是 returning next.handle(...),您实际上想要 return 一个首先调用以获取新令牌的可观察对象,然后执行下一个请求。

为了避免订阅,我们可以使用 switchMap 来为我们处理订阅:

intercept(req: HttpRequest<any>, next: HttpHandler) {
    return this.authTokenService.getAmadeusAuthToken$().pipe(
        switchMap(token => {
            const headers = req.headers.set('Authorization', `Bearer ${token.access_token}`);
            const authReq = req.clone({ headers });

            return next.handle(authReq);
        })
    );
}

这消除了我遇到的竞争条件,并确保请求在再次尝试请求之前等待新的令牌响应。这是一种快速而肮脏的方式,需要进一步改进以将令牌缓存在本地存储中并放入特定错误代码的过滤器

 export class AuthInterceptor implements HttpInterceptor {

  token :  Token;
  idTokenPresent = false;
  authRequest: any;
  idToken: string | string[] | null;
  testreq: any;
  constructor(private authTokenService: AuthTokenService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {

    return next.handle(req).pipe(
      catchError((response: HttpErrorResponse) => {
        return this.authTokenService.getAmadeusAuthToken$().pipe(
          switchMap(token => {
            this.authRequest = req.clone({
            headers: req.headers.append('Authorization', 'Bearer ' + token.access_token)
             });
            return next.handle(this.authRequest)
          })
        )
      }
    )
    )
  }
}