Angular Auth拦截器无法刷新令牌-Angular 7

时间:2019-04-12 09:33:39

标签: angular

如果刷新令牌已过期,我会尝试刷新访问令牌。登录后,我会收到两个令牌并将它们存储在本地存储中。服务器以状态401响应后,我尝试发送刷新令牌,但失败了,看来拦截器在标头内发送了berer访问令牌,而不是刷新令牌

身份验证拦截器

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  private isRefreshing = false;
  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  constructor(private authService: LoginService,
              private uploadService: ContractUploadService  ) { }


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

    if (this.authService.getJwtAccessToken()) {
      request = this.addToken(request, this.authService.getJwtAccessToken());
    }

    return next.handle(request).pipe(catchError(error => {
      if (error instanceof HttpErrorResponse && error.status === 401) {
        return this.handle401Error(request, next);
      } else {
        return throwError(error);
      }
    }));
  }

  addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      }
    });
  }

  handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken().pipe(
        finalize(() => this.isRefreshing = false),
        switchMap((token: any) => {
          if (token) {
            this.refreshTokenSubject.next(token.jwt);
            return next.handle(this.addToken(request, token.jwt));
          }
          this.authService.doLogoutUser();
          this.uploadService.stopUploadStatusChecker();
        }),
        catchError(error => {
          this.authService.doLogoutUser();
          this.uploadService.stopUploadStatusChecker();
          return throwError(error);
        })
      );
    } else {
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          return next.handle(this.addToken(request, jwt));
        }));
    }
  }
}

刷新令牌请求

  refreshToken() {
    return this.http
      .post<any>(BACK_END_URL_REFRESH, {
        'refresh_token': this.getRefreshToken()
      })
      .pipe(
        tap((tokens: any) => {
          this.storeJwtToken(tokens.jwt);
          this.isAuthenticated = true;
        }),
        catchError((err: any) => {
          console.log(err)
          this.doLogoutUser();
          return throwError(err);
        })
      );
  }

登录

  login(user: UserLogin) {
    const userData = new FormData();
    userData.append('user', user.name);
    userData.append('pwd', user.password);

    this.http.post<{ access_token: string; refresh_token: string }>(BACK_END_URL, userData).pipe(
      finalize(() => this.interactionService.setSpinnerStatus.next(false)),
    )
      .subscribe(
        response => {
          if (response.access_token) {
            this.isAuthenticated = true;
            this.interactionService.setSnackBar('User logged in successfully', 'success');
            this.storeTokens(response.refresh_token, response.access_token);
            this.extractUserInfoFromToken(response.access_token);
            this.router.navigate(['/user-panel']);
          }
        },
        error => {
          this.interactionService.setSnackBar('Wrong user name or password', 'error');
        }
      );
  }

本地存储方法

  private getRefreshToken() {
    return localStorage.getItem(this.REFRESH_TOKEN);
  }

  private storeJwtToken(jwt: string) {
    localStorage.setItem(this.JWT_ACCESS_TOKEN, jwt);
  }

  private storeTokens(refreshToken, accessToken) {
    localStorage.setItem(this.REFRESH_TOKEN, refreshToken);
    localStorage.setItem(this.JWT_ACCESS_TOKEN, accessToken);
  }

  private removeTokens() {
    localStorage.removeItem(this.JWT_ACCESS_TOKEN);
    localStorage.removeItem(this.REFRESH_TOKEN);
  }

[编辑] 尝试实施@Abdellah ASKI建议,但仍然无法正常工作

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

    if (this.authService.getJwtAccessToken() && request.headers.get('No-Auth') !== 'true') {
      request = this.addToken(request, this.authService.getJwtAccessToken());
    }

    return next.handle(request).pipe(catchError(error => {
      if (error instanceof HttpErrorResponse && error.status === 401) {
        return this.handle401Error(request, next);
      } else {
        return throwError(error);
      }
    }));
  }

 refreshToken() {
    return this.http
      .post<any>(BACK_END_URL_REFRESH, {
        refresh_token: this.getRefreshToken(),
        'No-Auth': 'true'
      })
      .pipe(
          tap((tokens: any) => {
            this.storeJwtToken(tokens.jwt);
            this.isAuthenticated = true;
          }),
            catchError((err: any) => {
              this.doLogoutUser();
              return throwError(err);
            })
      );

[Edit2]

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

    if (this.authService.getJwtAccessToken() && !request.headers.has('No-Auth')) {
      request = this.addToken(request, this.authService.getJwtAccessToken());
    }

    return next.handle(request).pipe(catchError(error => {
      if (error instanceof HttpErrorResponse && error.status === 401) {
        return this.handle401Error(request, next);
      } else {
        return throwError(error);
      }
    }));
  }

  addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      }
    });
  }

Headers

1 个答案:

答案 0 :(得分:0)

[已更新]

解决此问题的想法是,在每个您不需要发送访问令牌的请求上都添加一个名为No-Auth:true的标头。

因此,在您的代码中,您需要执行以下操作:

在您的refreshToken()函数中,您需要添加一个新的标头,如下所示:

refreshToken() {
    return this.http
      .post<any>(BACK_END_URL_REFRESH, {
        'refresh_token': this.getRefreshToken(),
        'No-Auth': 'true' <<-------<<-------<<-------<<-------
      })
      .pipe(
        ....
      );
  }

在Auth拦截器上,您需要检查此标头(如果存在),而无需添加访问令牌:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
    if (request.headers.has('No-Auth')) { <<-------<<-------<<-------
        return next.handle(request);
    }

    if (this.authService.getJwtAccessToken()) {
      request = this.addToken(request, this.authService.getJwtAccessToken());
    }

    ....
  }