Angular : guard
Achref El Mouelhi
Docteur de l’université d’Aix-Marseille
Chercheur en programmation par contrainte (IA)
Ingénieur en génie logiciel
[email protected]
H & H: Research and Training 1 / 19
Plan
1 Introduction
2 Création
3 Exemple avec CanActivate
4 Exemple avec CanDeactivate
H & H: Research and Training 2 / 19
Introduction
Angular
Guard ?
Un service Angular (donc décoré par @Injectable) qui
implémente une des interfaces suivantes H I ©
UEL
CanDeactivate : vérifie L M O
CanActivate : vérifie si un utilisateur peut visiter une route.
f E si un utilisateur peut quitter une route.
re : vérifie si un utilisateur peut visiter les routes
c h
CanActivateChild
enfants.A
©
CanLoad : vérifie si un utilisateur peut aller sur une route d’un
module défini avec un lazy loading
H & H: Research and Training 3 / 19
Introduction
Angular
Exemple
H I ©
UEL
On veut que l’accès à la route /adresse soit seulement autorisé
O
aux utilisateurs authentifiés
f E LM
ch r e
On va créer une guard auth et l’associer à la route adresse
©A
H & H: Research and Training 4 / 19
Création
Angular
Pour créer une guard
H I ©
EL
ng generate guard guard-name
O U
f E LM
ch r e
©A
H & H: Research and Training 5 / 19
Création
Angular
Pour créer une guard
H I ©
EL
ng generate guard guard-name
O U
f E LM
Ou le raccourci ch r e
ng g g guard-name ©A
H & H: Research and Training 5 / 19
Création
Angular
Pour notre exemple, on va créer une garde qui vérifie si un
utilisateur est authentifié avant de charger certaines routes
ng g g guards/auth
H I ©
UEL
O
f E LM
ch r e
©A
H & H: Research and Training 6 / 19
Création
Angular
Pour notre exemple, on va créer une garde qui vérifie si un
utilisateur est authentifié avant de charger certaines routes
ng g g guards/auth
H I ©
UEL
O
f E LM
Dans le menu qui s’affiche
ch r e
©A
Pointer sur CanActivate
Puis cliquer une première fois sur espace et une deuxième sur
entrée
H & H: Research and Training 6 / 19
Création
Angular
On peut aussi préciser dans la commande l’interface à
implémenter
H I ©
ng g g guards/auth --implements CanActivate
UEL
O
f E LM
ch r e
©A
H & H: Research and Training 7 / 19
Création
Angular
On peut aussi préciser dans la commande l’interface à
implémenter
H I ©
ng g g guards/auth --implements CanActivate
UEL
O
f E LM
ch r e
©A
Résultat
CREATE src/app/guards/auth.guard.spec.ts (346 bytes)
CREATE src/app/guards/auth.guard.ts (456 bytes)
H & H: Research and Training 7 / 19
Exemple avec CanActivate
Contenu du auth.guard.ts
import { Injectable } from ’@angular/core’;
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot,
UrlTree } from ’@angular/router’;
import { Observable } from ’rxjs’;
@Injectable({
providedIn: ’root’
})
H I ©
EL
export class AuthGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
O U
f E LM
state: RouterStateSnapshot): Observable<boolean | UrlTree> |
Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
ch r e
©A
}
}
H & H: Research and Training 8 / 19
Exemple avec CanActivate
Contenu du auth.guard.ts
import { Injectable } from ’@angular/core’;
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot,
UrlTree } from ’@angular/router’;
import { Observable } from ’rxjs’;
@Injectable({
providedIn: ’root’
})
H I ©
EL
export class AuthGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
O U
f E LM
state: RouterStateSnapshot): Observable<boolean | UrlTree> |
Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
ch r e
©A
}
}
ActivatedRouteSnapshot : contient des informations comme les paramètres envoyés
pour la route demandée...
RouterStateSnapshot :contient des informations comme l’URL de la route demandée
La méthode canActivate ne fait aucun contrôle car elle retourne toujours true
H & H: Research and Training 8 / 19
Exemple avec CanActivate
Angular
Associons AuthGuard à la route /adresse dans
app-routing.module.ts
const routes: Routes = [
// les autres routes
{
H I ©
path: ’adresse’,
UEL
O
LM
component: AdresseComponent,
canActivate: [AuthGuard]
r e f E
ch
},
©A
{ path: ’auth’, component: AuthComponent },
// le reste des routes
];
H & H: Research and Training 9 / 19
Exemple avec CanActivate
Angular
Associons AuthGuard à la route /adresse dans
app-routing.module.ts
const routes: Routes = [
// les autres routes
{
H I ©
path: ’adresse’,
UEL
O
LM
component: AdresseComponent,
canActivate: [AuthGuard]
r e f E
ch
},
©A
{ path: ’auth’, component: AuthComponent },
// le reste des routes
];
La route /auth va permettre d’exécuter le composant
AuthComponent et afficher et gérer l’authentification
H & H: Research and Training 9 / 19
Exemple avec CanActivate
Angular
Contenu de auth.component.html
<h1>Page d’authentification</h1>
<form (ngSubmit)="isAuthenticated()">
<div>
H I ©
EL
Nom d’utilisateur :
<input type=text [(ngModel)]=login name=login>
O U
LM
</div>
<div>
r e f E
ch
Mot de passe :
©A
<input type=text [(ngModel)]=password name=password>
<button type=submit>Se connecter</button>
</div>
<div [hidden]=’erreur’>Identifiants incorrects</div>
</form>
H & H: Research and Training 10 / 19
Exemple avec CanActivate
Contenu de auth.component.ts
import { Component, OnInit } from ’@angular/core’;
import { Router } from ’@angular/router’;
@Component({
selector: ’app-auth’,
templateUrl: ’./auth.component.html’,
styleUrls: [’./auth.component.css’]
})
H I ©
EL
export class AuthComponent implements OnInit {
erreur = true;
password = ’’;
O U
login = ’’;
f E
constructor(private router: Router) { } LM
ngOnInit() { }
ch r e
©A
isAuthenticated() {
if (this.login === ’wick’ && this.password === ’john’) {
localStorage.setItem(’isConnected’, ’true’);
this.router.navigateByUrl(’/personne’);
} else {
this.erreur = false;
}
}
}
H & H: Research and Training 11 / 19
Exemple avec CanActivate
Mettons à jour le contenu de auth.guard.ts
import { Injectable } from ’@angular/core’;
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot,
Router } from ’@angular/router’;
@Injectable({
providedIn: ’root’
})
export class AuthGuard implements CanActivate {
H I ©
U EL
MO
constructor(private router: Router) { }
canActivate(
f E L
r
next: ActivatedRouteSnapshot,
ch e
state: RouterStateSnapshot): boolean {
return true;
} else {
©A
if (Boolean(localStorage.getItem(’isConnected’))) {
this.router.navigateByUrl(’/auth’);
return false;
}
}
}
H & H: Research and Training 12 / 19
Exemple avec CanActivate
Angular
Pour tester H I ©
UEL
O
Essayez d’accéder à la route /adresse sans authentification
f E LM
ch r e
Authentifiez-vous avec les identifiants wick et john et réessayez
©A
H & H: Research and Training 13 / 19
Exemple avec CanDeactivate
Angular
Remarque
Préciser l’interface à implémenter pendant la génération existe depuis Angular 8
Angular-cli ne propose pas l’interface CanDeactivate
On va spécifier l’interface CanActivate puis on modifie
H I ©
U EL
O
f E LM
ch r e
©A
H & H: Research and Training 14 / 19
Exemple avec CanDeactivate
Angular
Remarque
Préciser l’interface à implémenter pendant la génération existe depuis Angular 8
Angular-cli ne propose pas l’interface CanDeactivate
On va spécifier l’interface CanActivate puis on modifie
H I ©
U EL
O
f E LM
Exécutons la commande suivante
ch r e
©A
ng g g guards/leave
H & H: Research and Training 14 / 19
Exemple avec CanDeactivate
Angular
Remarque
Préciser l’interface à implémenter pendant la génération existe depuis Angular 8
Angular-cli ne propose pas l’interface CanDeactivate
On va spécifier l’interface CanActivate puis on modifie
H I ©
U EL
O
f E LM
Exécutons la commande suivante
ch r e
©A
ng g g guards/leave
Le résultat
CREATE src/app/guards/leave.guard.spec.ts (352 bytes) CREATE
src/app/guards/leave.guard.ts (472 bytes)
H & H: Research and Training 14 / 19
Exemple avec CanDeactivate
Code généré
@Injectable({
providedIn: ’root’
})
export class LeaveGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree>
H I ©
| Promise<boolean | UrlTree> | boolean | UrlTree {
UEL
return true;
O
}
}
f E LM
ch r e
©A
H & H: Research and Training 15 / 19
Exemple avec CanDeactivate
Code généré
@Injectable({
providedIn: ’root’
})
export class LeaveGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree>
H I ©
| Promise<boolean | UrlTree> | boolean | UrlTree {
UEL
return true;
O
}
}
f E LM
ch r e
Ensuite
© A
Remplacez CanActivate par CanDeactivate<FormulaireComponent>
Faites l’import pour CanDeactivate
Supprimer la méthode générée pour CanActivate et ajouter la méthode de
l’interface qu’il faut implémenter
H & H: Research and Training 15 / 19
Exemple avec CanDeactivate
Nouveau code
@Injectable({
providedIn: ’root’
})
export class LeaveGuard implements CanDeactivate<FormulaireComponent> {
canDeactivate(component: FormulaireComponent,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): boolean {
H I ©
EL
throw new Error("Method not implemented.");
}
}
O U
f E LM
ch r e
©A
H & H: Research and Training 16 / 19
Exemple avec CanDeactivate
Nouveau code
@Injectable({
providedIn: ’root’
})
export class LeaveGuard implements CanDeactivate<FormulaireComponent> {
canDeactivate(component: FormulaireComponent,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot): boolean {
H I ©
EL
throw new Error("Method not implemented.");
}
}
O U
f E LM
Objectif
ch r e
©A
On ajoute le lien suivant dans formulaire.component.html :
<a routerLink=’/personne’>aller ailleurs</a>
Si l’utilisateur remplit les deux champs nom et prenom dans
formulaire.component.html et clique sur le lien pour aller sur le composant
personne, on lui demande une confirmation.
H & H: Research and Training 16 / 19
Exemple avec CanDeactivate
Angular
Modifions la garde
@Injectable({
providedIn: ’root’
})
H I ©
EL
export class LeaveGuard implements CanDeactivate<FormulaireComponent> {
canDeactivate(component: FormulaireComponent,
currentRoute: ActivatedRouteSnapshot,
O U
currentState: RouterStateSnapshot,
f E LM
nextState?: RouterStateSnapshot): boolean {
r e
return component.personne.nom === undefined ||
ch
©A
component.personne.prenom === undefined ||
component.personne.nom.length === 0 ||
component.personne.prenom.length === 0 ||
confirm(’voulez-vous vraiement quitter ?’);
}
}
H & H: Research and Training 17 / 19
Exemple avec CanDeactivate
Angular
Associons LeaveGuard à la route /formulaire dans
app-routing.module.ts
const routes: Routes = [
// les autres routes
{
path: ’adresse’,
H I ©
component: AdresseComponent,
UEL
O
LM
canActivate: [AuthGuard]
},
{
r e f E
ch
©A
path: ’formulaire’,
component: FormulaireComponent,
canDeactivate: [LeaveGuard]
},
{ path: ’auth’, component: AuthComponent },
// le reste des routes
];
H & H: Research and Training 18 / 19
Exemple avec CanDeactivate
Angular
Il est possible d’associer plusieurs guards à une route
const routes: Routes = [
// les autres routes
{
path: ’adresse’,
component: AdresseComponent,
H I ©
canActivate: [AuthGuard]
UEL
O
LM
},
{
path: ’formulaire’,
r e f E
ch
©A
component: FormulaireComponent,
canActivate: [AuthGuard],
canDeactivate: [LeaveGuard],
},
{ path: ’auth’, component: AuthComponent },
// le reste des routes
];
H & H: Research and Training 19 / 19