85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
import { Injectable } from '@angular/core';
|
|
import {
|
|
HttpEvent,
|
|
HttpHandler,
|
|
HttpInterceptor,
|
|
HttpRequest,
|
|
HttpErrorResponse,
|
|
} from '@angular/common/http';
|
|
import { Observable, throwError, BehaviorSubject } from 'rxjs';
|
|
import { catchError, switchMap, filter, take, finalize } from 'rxjs/operators'; // Import finalize
|
|
import { AuthService } from './auth.service';
|
|
|
|
@Injectable()
|
|
export class JwtInterceptor implements HttpInterceptor {
|
|
private isRefreshing = false;
|
|
// Initialize refreshTokenSubject with null
|
|
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
|
|
|
|
constructor(private authService: AuthService) {}
|
|
|
|
intercept(
|
|
request: HttpRequest<any>,
|
|
next: HttpHandler
|
|
): Observable<HttpEvent<any>> {
|
|
if (request.url.includes('/auth/refresh')) {
|
|
return next.handle(request);
|
|
}
|
|
|
|
const accessToken = this.authService.getAccessToken();
|
|
if (accessToken) {
|
|
request = this.addToken(request, accessToken);
|
|
}
|
|
|
|
return next.handle(request).pipe(
|
|
catchError((error) => {
|
|
if (error instanceof HttpErrorResponse && error.status === 401) {
|
|
return this.handle401Error(request, next);
|
|
}
|
|
return throwError(() => error);
|
|
})
|
|
);
|
|
}
|
|
|
|
private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
|
|
if (!this.isRefreshing) {
|
|
this.isRefreshing = true;
|
|
// Reset the refreshTokenSubject to null so that subsequent requests will wait
|
|
// this.refreshTokenSubject.next(null);
|
|
this.refreshTokenSubject = new BehaviorSubject<any>(null);
|
|
|
|
|
|
return this.authService.refreshToken().pipe(
|
|
switchMap((token: any) => {
|
|
this.refreshTokenSubject.next(token.accessToken);
|
|
return next.handle(this.addToken(request, token.accessToken));
|
|
}),
|
|
catchError((err) => {
|
|
// If refresh fails, logout the user
|
|
this.authService.clientSideLogout();
|
|
return throwError(() => err);
|
|
}),
|
|
finalize(() => {
|
|
// When the refresh attempt completes, set isRefreshing to false
|
|
this.isRefreshing = false;
|
|
})
|
|
);
|
|
} else {
|
|
// If a refresh is already in progress, wait for it to complete
|
|
return this.refreshTokenSubject.pipe(
|
|
filter(token => token != null),
|
|
take(1),
|
|
switchMap(jwt => next.handle(this.addToken(request, jwt)))
|
|
);
|
|
}
|
|
}
|
|
|
|
private addToken(request: HttpRequest<any>, token: string) {
|
|
return request.clone({
|
|
setHeaders: {
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
});
|
|
}
|
|
}
|