Angular 6 HttpInterceptor - when getting 401 refresh the token and create the same request

℡╲_俬逩灬. 提交于 2021-01-24 07:46:04

问题


I'm using the HttpInterceptor in Angular 6, and trying to built a refresh token mechanisim:

When httpClient request get's 401 status code (unauthorised) the HttpInterceptor will create a request that will refresh the token, it will update the headers of the first request and call it again with the new token.

The code is working until the stage that I need to recall the original request again with the new token that got from the refresh token request. This is my code:

export class MyInterceptor implements HttpInterceptor {

constructor(public restService:RestService){}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
 return next.handle(request).pipe(
    tap(event => {
      if (event instanceof HttpResponse) {
        console.log('succeed');
      }
    }, error => {
        if(error.status==401){
            this.restService.refreshToken().subscribe(response => {
                this.restService.updateHeaders(response['token']);
                const newRequest = request.clone();
                return next.handle(newRequest);
              });
        }
    })
  )
}
}

回答1:


You need to do something like below. You also need to make sure the new header will be appended to the request. Not sure where you do it, since it's not in this interceptor. The best part to append it would be in an interceptor. Even this one, in case you're actually doing it in the services.

// if multiple requests fail, do only one refresh request
private readonly refreshToken$ = this.restService
    .refreshToken() //the refresh token method could update the token in it's internal state, not sure why the later call to updateHeaders
    .pipe(
        tap(response => this.restService.updateHeaders(response['token'])),
        ignoreElements(),
        shareReplay(1)
    );

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next
        .handle(request)
        .pipe(
            catchError(error => {
                if (error.status === 401) {
                    return concat(this.refreshToken$, throwError(new RetryRequestError()));
                } else {
                    throw error;
                }
            }),
            retryWhen(error => {
                if (error instanceof RetryRequestError) {
                    // try the request again
                    return;
                }
                throw error;
            })
        );
}

class RetryRequestError extends Error {
    constructor() {
        super('retry_request');
        Object.setPrototypeOf(this, RetryRequestError.prototype);
    }
}



回答2:


I read more about it, and used a code that some one wrote, and I changed it a little bit and modified it, and finnaly it worked for me. of course that if someone use this code he should modified it.

import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { catchError, switchMap } from 'rxjs/operators';
import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpSentEvent, HttpHeaderResponse, HttpProgressEvent, HttpResponse, HttpUserEvent, HttpErrorResponse } from "@angular/common/http";
import { _throw as observableThrowError } from 'rxjs/observable/throw';
import { Router } from "@angular/router";
import { environment } from '../../../environments/environment'

@Injectable()
export class RequestInterceptorService implements HttpInterceptor {

    public endPoints;

    constructor(public httpClient: HttpClient, public router: Router) { this.endPoints = environment.endPoints; }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
        return <any>next.handle(req.clone({ headers: req.headers.set('Cache-Control', 'no-cache').set('Pragma', 'no-cache'), withCredentials: true })).pipe(
            catchError(error => {
                if (req.url.indexOf('refresh_token_login') != -1 && ((<HttpErrorResponse>error).status) == 401) {//the app created request for getting new token/session and got 401,meaning the refresh token/session also expired
                    this.router.navigate(['/logout']);
                }
                else if (((<HttpErrorResponse>error).status) == 401 && (<HttpErrorResponse>error).error.error_code == 401001) { // 401001 meaning that the token is invalid
                    this.router.navigate(['/logout']);
                }
                else if (((<HttpErrorResponse>error).status) == 401 && (<HttpErrorResponse>error).error.error_code == 401002) { // 401002 meaning that the token has expired
                    return this.handle401Error(req, next);
                } else {
                    return observableThrowError(error.error);
                }
            }));
    }

    handle401Error(req: HttpRequest<any>, next: HttpHandler) {
        return this.refreshToken().pipe(
            switchMap((res) => {
                if (res.status == 200) {
                    return next.handle(this.getNewRequest(req));
                }else{
                    return this.logoutUser();
                }
            }),
            catchError(error => { 
                   return next.handle(this.getNewRequest(req));
            })
        )
    }

    getNewRequest(req: HttpRequest<any>): HttpRequest<any> {
        return req.clone({ headers: req.headers.set('Cache-Control', 'no-cache').set('Pragma', 'no-cache'), withCredentials: true });
    }

    logoutUser() {
        this.router.navigate(['/logout']);
        return observableThrowError("");
    }

    refreshToken() {
        return this.httpClient.get(this.endPoints.refreshToken, { observe: 'response' }).pipe(
            catchError(error => {
                return observableThrowError(error);
            }));
    }
}


来源:https://stackoverflow.com/questions/51786002/angular-6-httpinterceptor-when-getting-401-refresh-the-token-and-create-the-sa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!