Auth : rejeter les jetons dont le compte n'existe plus (validation de session)
Corrige un contournement : après réinitialisation de la base (même JWT_SECRET_KEY), un jeton restait cryptographiquement valide et donnait accès alors que le compte n'existait plus, permettant d'atteindre l'onboarding sans s'inscrire. - Backend : JwtBearer.OnTokenValidated vérifie désormais l'existence du compte référencé par le claim sub (lu sous 'sub' ou NameIdentifier selon le remapping) et rejette le jeton (401) si le compte est introuvable. - Backend : nouvel endpoint protégé GET /api/auth/moi (SessionController) renvoyant 200 si la session est réellement valide, 401 sinon. - Frontend : authGuard valide la session côté serveur (GET /auth/moi) au lieu de se fier au seul jeton local ; sur échec, redirection vers /login (jeton purgé par l'intercepteur sur 401). AuthService.validerSession() ajouté. Tests backend : 54/54 au vert.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { CanActivateFn, Router, UrlTree } from '@angular/router';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
import { AuthService } from '../services/auth.service';
|
||||
|
||||
@@ -8,17 +10,30 @@ import { AuthService } from '../services/auth.service';
|
||||
* authentification.
|
||||
*
|
||||
* Comportement (Exigences 4.6, 9.3) :
|
||||
* - Si `AuthService.estAuthentifie()` est vrai → navigation autorisée (retourne `true`).
|
||||
* - Sinon → redirection vers `/login` (retourne un `UrlTree`), ce qui bloque l'accès
|
||||
* à la route protégée tant que l'utilisateur n'est pas connecté. (Exigences 4.6, 9.3)
|
||||
* - Si aucun jeton n'est présent localement → redirection immédiate vers `/login`.
|
||||
* - Sinon, la session est VALIDÉE côté serveur via `GET /api/auth/moi` (endpoint
|
||||
* protégé) : cela garantit que le jeton est réellement valide ET que le compte
|
||||
* existe toujours. Un jeton « fantôme » (cryptographiquement valide mais dont le
|
||||
* compte a été supprimé, ex. base réinitialisée) est ainsi rejeté (401) au lieu de
|
||||
* donner accès. En cas d'échec, on redirige vers `/login` (le jeton est purgé par
|
||||
* l'intercepteur d'authentification sur le 401).
|
||||
*
|
||||
* Elle se compose avec la `profilConfigureGuard` existante : sur les routes de données,
|
||||
* on applique `[authGuard, profilConfigureGuard]` (l'authentification est vérifiée d'abord,
|
||||
* puis la configuration du profil).
|
||||
* on applique `[authGuard, profilConfigureGuard]` (authentification vérifiée d'abord,
|
||||
* puis configuration du profil).
|
||||
*/
|
||||
export const authGuard: CanActivateFn = (): boolean | UrlTree => {
|
||||
export const authGuard: CanActivateFn = (): Observable<boolean | UrlTree> => {
|
||||
const authService = inject(AuthService);
|
||||
const router = inject(Router);
|
||||
|
||||
return authService.estAuthentifie() ? true : router.createUrlTree(['/login']);
|
||||
// Pas de jeton local : inutile d'interroger le serveur, on redirige directement.
|
||||
if (!authService.estAuthentifie()) {
|
||||
return of(router.createUrlTree(['/login']));
|
||||
}
|
||||
|
||||
// Jeton présent : on confirme sa validité réelle auprès du serveur.
|
||||
return authService.validerSession().pipe(
|
||||
map(() => true as boolean | UrlTree),
|
||||
catchError(() => of(router.createUrlTree(['/login'])))
|
||||
);
|
||||
};
|
||||
|
||||
@@ -55,6 +55,15 @@ export class AuthService {
|
||||
return this.http.get<{ existe: boolean }>(`${this.baseUrl}/compte-existe`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide la session côté serveur (GET /auth/moi, endpoint protégé).
|
||||
* 200 => le jeton est valide ET le compte existe ; toute erreur (401, etc.)
|
||||
* signifie que la session n'est pas réellement valide.
|
||||
*/
|
||||
validerSession(): Observable<{ authentifie: boolean }> {
|
||||
return this.http.get<{ authentifie: boolean }>(`${this.baseUrl}/moi`);
|
||||
}
|
||||
|
||||
/** Retourne le token courant, ou null si non authentifié. */
|
||||
getToken(): string | null {
|
||||
return this._token();
|
||||
|
||||
Reference in New Issue
Block a user