Skip to content

Commit

Permalink
feat(App): intercept request behind Auth and play refreshToken if nec…
Browse files Browse the repository at this point in the history
…essary
  • Loading branch information
cboucheIGN committed Nov 28, 2024
1 parent 965f121 commit 957db5a
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 67 deletions.
16 changes: 16 additions & 0 deletions public/artwork/background/ovoid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 51 additions & 0 deletions public/artwork/pictograms/document/document-download.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions public/artwork/pictograms/document/document.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions public/artwork/pictograms/system/technical-error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
<router-outlet></router-outlet>
</main>

<footer id="footer" tabindex="-1">
<footer id="footer" tabindex="-1" class="fr-mt-16v">
<app-footer></app-footer>
</footer>
9 changes: 4 additions & 5 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ export const routes: Routes = [
component: HomeComponent
},
{
path: 'requete',
loadChildren: () => import('./requete/requete.module').then(m => m.RequeteModule)
path: 'accueil',
component: HomeComponent
},
{
path: 'login',
component: MesForetsComponent,
title: 'Mes Forêts'
path: 'requete',
loadChildren: () => import('./requete/requete.module').then(m => m.RequeteModule)
},
{
path: 'mes-forets',
Expand Down
6 changes: 5 additions & 1 deletion src/app/components/header/header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ export class HeaderComponent {

headerToolsLinks: any = DEFAULT_HEADER_TOOLS_LINKS;

menuHeader: any = [];
menuHeader: any = [
{ label: 'Découvrir', routerLink: '/accueil' },
{ label: 'Nouvelle requête', routerLink: '/requete/nouvelle' },
{ label: 'Mes forêts', routerLink: '/mes-forets' },
];

constructor(
private tokenService: TokenService,
Expand Down
66 changes: 40 additions & 26 deletions src/app/core/interceptors/app-token.interceptor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { HttpContextToken, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable, Injector } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, map, Observable, throwError } from 'rxjs';
import { catchError, map, Observable, switchMap, throwError } from 'rxjs';

import { TokenService } from '../../shared/services/token.service';
import { environment } from '../../../environments/environment';
import { LoginService } from '../../shared/services/login.service';

export const INTERCEPT = new HttpContextToken(() => false);

Expand All @@ -22,16 +23,12 @@ export class AppTokenInterceptor implements HttpInterceptor {
if (!request.context.get(INTERCEPT)) {
return next.handle(request);
}

console.log('intercept', request.url);

if (!this.hasToken()) {
return next.handle(request);
}
console.log('[AppTokenInterceptor]', 'intercept', request.url);

request = request.clone({
headers: request.headers.set('Authorization', `Bearer ${this.getToken()}`)
});
if (this.hasToken()) {
request = this.addToken(request);
}

return next.handle(request).pipe(
map((event: HttpEvent<any>) => event),
Expand All @@ -41,10 +38,11 @@ export class AppTokenInterceptor implements HttpInterceptor {
this.router.navigate(['/']);
} else if (error.status === 404) {
this.router.navigate(['/', '404']);
} else if (error.status === 403 || error.status === 401) {
// this.alertUser('Votre authentification est invalide ou expirée. Veuillez vous reconnecter.');
console.log('Votre authentification est invalide ou expirée. Veuillez vous reconnecter.');
window.location.href = environment.loginUrl;
} else if (error.status === 403) {
this.alertUser('Votre authentification ne vous donne pas accès a ce contenu.');
} else if (error.status === 401) {
this.alertUser('Votre authentification[token] est invalide ou expirée. Veuillez vous reconnecter.');
return this.handleTokenExpired(request, next);
} else {
// this.alertUser('Une erreur serveur est survenue.');
}
Expand All @@ -55,24 +53,40 @@ export class AppTokenInterceptor implements HttpInterceptor {
}


private alertUser(message: string) {
alert(message);
private handleTokenExpired(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const loginService = this.injector.get(LoginService);
return loginService.refreshAccessToken().pipe(
switchMap(() => {
// Retry the original request with the new access token
return next.handle(this.addToken(request));
}),
catchError((error) => {
// Handle refresh token error (e.g., redirect to login page)
console.error('Error handling expired access token:', error);
return throwError(() => error);
})
);
}


private addToken(request: HttpRequest<any>): HttpRequest<any> {
const tokenService = this.injector.get(TokenService);
return request.clone({
setHeaders: {
Authorization: `Bearer ${tokenService.getToken()}`,
},
});
}


private hasToken() {
const loginRegisterService = this.injector.get(TokenService);
return loginRegisterService.hasToken();
const tokenService = this.injector.get(TokenService);
return tokenService.hasToken();
}

/**
* Lecture du token depuis le localStorage du navigateur
* @returns le jeton d'authentification s'il existe
* @memberOf AppTokenInterceptor
*/
private getToken() {
const loginRegisterService = this.injector.get(TokenService);
return loginRegisterService.getToken();

private alertUser(message: string) {
console.warn('[AppTokenInterceptor]', message);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const EXPORT_TILE_CONFIG = [
size: 'MD',
download: false,
artworkDirPath: 'artwork',
artworkFilePath: 'artwork/pictograms/buildings/city-hall.svg',
artworkFilePath: 'artwork/pictograms/document/document-download.svg',
detail: 'Détail (optionnel)'
},
{
Expand All @@ -36,7 +36,7 @@ const EXPORT_TILE_CONFIG = [
size: 'MD',
download: false,
artworkDirPath: 'artwork',
artworkFilePath: 'artwork/pictograms/buildings/city-hall.svg',
artworkFilePath: 'artwork/pictograms/document/document.svg',
detail: 'Détail (optionnel)'
}
];
Expand Down
6 changes: 3 additions & 3 deletions src/app/shared/services/foret.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ export class ForetService {

list(): Observable<Foret[]> {
const url = `${this.apiUrl}/forets`;
return this.http.get(url, { headers: this.getHeaders(), context: this.getContext() }).pipe(
return this.http.get(url, { headers: this.getHeaders(), context: this.getInterceptContext() }).pipe(
map((response: any) => response?.map((f: any) => new Foret().deserialise(f)))
);
}

getForet(id: string): Observable<Foret> {
const url = `${this.apiUrl}/forets/${id}`;
return this.http.get(url, { headers: this.getHeaders(), context: this.getContext() }).pipe(
return this.http.get(url, { headers: this.getHeaders(), context: this.getInterceptContext() }).pipe(
map((response: any) => new Foret().deserialise(response))
);
}
Expand All @@ -45,7 +45,7 @@ export class ForetService {
});
}

private getContext() {
private getInterceptContext() {
return new HttpContext().set(INTERCEPT, true);
}

Expand Down
Loading

0 comments on commit 957db5a

Please sign in to comment.