typescript - Angular 6 Interceptor HTTP Gestionarea reîmprospătării token-ului 401
Am construit AuthInterceptor-ul meu care, la o eroare 401, trimite o cerere pentru a obține un token nou.
Metoda handle401Error este apelată atunci când întâlnesc o eroare 401, dar se pare că nu primesc niciun răspuns în this.authService.refreshToken().pipe()
InterceptorAutentificare
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))
)
}
}
}
Token de reîmprospătare AuthService
refreshToken(): Observable<string> {
console.log('refreshToken');
let token = 'xxx-xxx-xx';
return of(token).pipe(delay(1000));
}
Răspuns #1
Pe lângă returnarea lipsă în 'cazul 401', iată cum aș gestiona asta.
Ideea de bază este că doriți să reîncercați întregul observable odată ce primiți noul token de reîmprospătare. De asemenea, cererea este modificată într-un observable astfel încât la fiecare reîncercare să primească noul token de la serviciul de autentificare.
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;
})
)
)
);
}
}
