简体   繁体   English

Angular 6 HTTP拦截器刷新令牌401处理

[英]Angular 6 HTTP Interceptor Refresh token 401 handling

I have built my AuthInterceptor which on a 401 error sends a request to get a new token. 我建立了我的AuthInterceptor,它在401错误上发送了一个获取新令牌的请求。

The handle401Error method is called when I encounter a 401 error, But I don't seem to be getting any response in my this.authService.refreshToken().pipe() 当我遇到401错误时,将调用handle401Error方法,但是我的this.authService.refreshToken()。pipe()似乎没有任何响应

AuthInterceptor 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 Refresh Token AuthService刷新令牌

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

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

Besides the missing return in 'case 401', here's how I would handle it. 除了“案例401”中缺少的收益外,这就是我的处理方式。

The basic idea is that you want to retry the entire observable once you receive the new refresh token. 基本思想是,一旦收到新的刷新令牌,您便想重试整个可观察的对象。 Also, the request is patched inside an observable so that on each retry it will get the new token from the auth service. 同样,该请求被修补在一个可观察的内部,以便在每次重试时它将从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;
          })
        )
      )
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM