Angular 6 HTTP拦截器刷新令牌401处理 [英] Angular 6 HTTP Interceptor Refresh token 401 handling

查看:63
本文介绍了Angular 6 HTTP拦截器刷新令牌401处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have built my AuthInterceptor which on a 401 error sends a request to get a new token.

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

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()

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));
}

推荐答案

除了案例401"中缺少的收益外,这就是我的处理方式.

Besides the missing return in 'case 401', here's how I would handle it.

基本思想是,您希望在收到新的刷新令牌后重试整个可观察的对象.另外,该请求被修补在一个可观察的内部,以便每次重试时都会从auth服务获取新令牌.

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.

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;
          })
        )
      )
    );
  }
}

这篇关于Angular 6 HTTP拦截器刷新令牌401处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆