【问题标题】:Angular 6 HTTP Interceptor Refresh token 401 handlingAngular 6 HTTP拦截器刷新令牌401处理
【发布时间】:2018-10-09 11:35:01
【问题描述】:

我已经构建了我的 AuthInterceptor,它在 401 错误时发送请求以获取新令牌。

遇到 401 错误时会调用 handle401Error 方法,但我的 this.authService.refreshToken().pipe() 中似乎没有得到任何响应

AuthInterceptor

import { Injectable, Injector } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, tap, switchMap } from 'rxjs/operators';
import { AuthService } from '../services/auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  isRefreshingToken:boolean = false;
  constructor(public authService: AuthService, private injector: Injector) {}

    addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
        return req.clone({ setHeaders: {
          Authorization: 'Bearer ' + token,
          'Content-Type': 'application/json'
       }})
    }

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

    request = this.addToken(request, this.authService.getToken())
    return next.handle(request).pipe (
      catchError((error: Error) => {
        if(error instanceof HttpErrorResponse){
          console.log('err', error);
          switch(error.status) {
            case 401:
            this.handle401Error(request, next)
            default:
            return throwError(error);
          }

        } else {
          return throwError(error);
        }
      })
    );
  }

  handle401Error(request: HttpRequest<any>, next: HttpHandler){
    console.log('handle 401');
    if(!this.isRefreshingToken) { //do not send another refresh token request if already in progress
      this.isRefreshingToken = true;

      return this.authService.refreshToken().pipe(
        switchMap((newToken: string) => {
          console.log('newToken', newToken) // I DO NOT GET A VALUE HERE
            if (newToken) { 
              return next.handle(this.addToken(request, newToken));
            }

        }),
        catchError((error) => {
          console.log('error', error) //NOR DO I GET AN ERROR
          return throwError(error)
        }),
        tap(data => console.log(data))
      )
    }
  }
}

AuthService 刷新令牌

refreshToken(): Observable<string> {
    console.log('refreshToken');
    let token = 'xxx-xxx-xx';

    return of(token).pipe(delay(1000));
}

【问题讨论】:

  • case 401,你需要return this.handle401Error(request, next)。另外,如果isRefreshingToken 为真,会发生什么。刷新令牌后不想重试请求吗?
  • 难以置信,不知道我怎么错过了退货声明。如果 refreshToken 为真,Yes 将处理该条件。非常感谢您指出这一点
  • @Neil 你解决了这个问题吗?同样的事情发生在我身上
  • @usmansaleem 您具体面临什么问题?你有堆栈闪电战示例吗?

标签: angular typescript angular-http-interceptors


【解决方案1】:

除了“案例 401”中缺少的返回之外,这是我将如何处理它。

基本思想是,一旦收到新的刷新令牌,您希望重试整个 observable。此外,该请求在 observable 中进行了修补,以便在每次重试时,它都会从 auth 服务获取新令牌。

import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { Observable } from 'rxjs';
import { catchError, retryWhen, switchMap, tap } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private retryRequest = Symbol('reload');
  private refreshToken = this.authService.refreshToken()
    .pipe(
      tap(newToken => {
        if (newToken) {
          throw this.retryRequest;
        }
      }),
      share(),
    ) as Observable<any>;

  constructor(public authService: AuthService) { }

  private addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
    return req.clone({
      setHeaders: {
        Authorization: 'Bearer ' + token,
        'Content-Type': 'application/json'
      }
    });
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const request$ = new Observable<HttpRequest<any>>(observer => {
      observer.next(this.addToken(request, this.authService.getToken()));
      observer.complete();
    });

    return request$.pipe(
      switchMap(req => next.handle(req)),
      catchError((error: Error) => {
        if (error instanceof HttpErrorResponse) {
          switch (error.status) {
            case 401:
              return this.refreshToken;
            default:
              throw error;
          }
        } else {
          throw error;
        }
      }),
      retryWhen(err$ =>
        err$.pipe(
          tap(err => {
            if (err === this.retryRequest) { return; }
            throw err;
          })
        )
      )
    );
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-31
    • 2018-06-12
    • 2019-03-28
    • 2018-06-14
    • 2021-11-12
    • 2018-06-02
    • 2017-12-26
    • 2019-09-03
    相关资源
    最近更新 更多