Skip to content

Instantly share code, notes, and snippets.

@filipemansano
Last active April 17, 2024 17:44
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save filipemansano/3b2cf22b1893261c5901a746e078d742 to your computer and use it in GitHub Desktop.
Save filipemansano/3b2cf22b1893261c5901a746e078d742 to your computer and use it in GitHub Desktop.
Interceptador HTTP em Angular 6 para adicionar o Token JWT nos request, e renovar o token caso expirado funcionando com múltiplas chamadas
import {throwError as observableThrowError, Observable , BehaviorSubject } from 'rxjs';
import { Injectable, Injector } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import { finalize , catchError , switchMap , take , filter } from 'rxjs/operators';
import { AuthService } from '@app/core/security/auth/auth.service';
/**
* Interceptador HTTP para adicionar o Token nas requisições ao serve
* e mapear os erros a fim de verificar erro de token expirado
* tentando renova-lo caso possivel, aceitando multiplas chamadas assincronas
* com o token expirado criando uma espece de "fila" até que a 1º chamada que
* solicitou o token seja resolvida.
*
* @author Filipe Mansano
* @version 1.0
* @since 2018-01-02
*/
@Injectable()
export class JWTInterceptor implements HttpInterceptor {
isRefreshingToken: boolean = false;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
constructor(private inj: Injector) { }
/**
* Função que clona o request adicionando o token nos cabeçalhos
* @param request
* @param token
*/
addToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authService = this.inj.get(AuthService);
/**
* no login nao quero interceptar nada, então
* do continuidade no fluxo do request
*/
if (request.url.includes("/auth/login")) {
return next.handle(request);
}
const requestJWT = this.addToken(request, authService.getToken().token);
// capturando os possiveis erros do request
return next.handle(requestJWT).pipe(
catchError(err => {
/**
* Caso o erro seja um código 401
* inicio a logica pra o refresh do token
*/
if (err.status === 401) {
// verifico se o motivo foi token expirado
if (err.error && err.error.errorMessage.includes("expirado")) {
// se o refresh de token não tiver em andamento, inicio ele
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
/**
* Reiniciando o valor do token aqui para que os proximos pedidos
* aguardem até que o token volte da chamada de atualização do token.
*/
this.tokenSubject.next(null);
return authService.refreshToken().pipe(
finalize(() => {
this.isRefreshingToken = false;
}),
switchMap((newToken: string) => {
if(newToken){
this.tokenSubject.next(newToken);
return next.handle(this.addToken(request, newToken));
}
/**
* se não for retornado o token, deu algum problema
* então desconecto o usuario e lanço a exceção pra frente
*/
authService.logoff();
return observableThrowError("Não foi possivel obter o token");
}),
/**
* Caso de qualquer erro no refresh do token
* não tem oque fazer, então deslogo o usuario
*/
catchError(errTokenRefresh => {
authService.logoff();
return observableThrowError(errTokenRefresh);
})
);
}
/**
* Caso o token esteja em processe de atualização
*/
else {
return this.tokenSubject.pipe(
filter(token => token != null),
take(1),
switchMap(token => {
return next.handle(this.addToken(request,token));
})
);
}
}
/**
* Caso o motivo do erro 401 não contenha a palavra expirado
* deslogo o usuario, pois é algum erro desconhecido...
*/
else {
authService.logoff();
return observableThrowError(err);
}
}
// qualquer outro erro lanço uma exceção
else{
return observableThrowError(err);
}
})
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment