Académique Documents
Professionnel Documents
Culture Documents
Achref El Mouelhi
elmouelhi.achref@gmail.com
1 Introduction
2 JWT
3 HttpInterceptor
4 Guard CanActivate
5 Déconnexion
Angular
Objectif de ce chapitre
Considérons les fichiers suivant qui permettent de communiquer avec une ressource
REST (PHP, Java, C#...) en lecture et écriture (le code est donné dans les slides
suivantes)
H I ©
EL
app.module.ts
U
MO
personne.ts
E L
personne.component.ts
f
ch r e
personne.component.html
© A
personne.component.css
personne.service.ts
Les ressources REST nécessite une authentification (avec JWT) et une autorisation
Angular
Objectif de ce chapitre
Considérons les fichiers suivant qui permettent de communiquer avec une ressource
REST (PHP, Java, C#...) en lecture et écriture (le code est donné dans les slides
suivantes)
H I ©
EL
app.module.ts
U
MO
personne.ts
E L
personne.component.ts
f
ch r e
personne.component.html
© A
personne.component.css
personne.service.ts
Les ressources REST nécessite une authentification (avec JWT) et une autorisation
Contenu de app.module.ts
@NgModule({
H I ©
EL
declarations: [
AppComponent,
O U
LM
AdresseComponent,
PersonneComponent,
FormulaireComponent
r e f E
ch
],
©A
imports: [
BrowserModule,
FormsModule,
HttpClientModule
],
providers: [PersonneService],
bootstrap: [AppComponent]
})
export class AppModule { }
Angular
Contenu de personne.ts
H I ©
export interface Personne {
UEL
id?: number;
O
nom?: string;
f E LM
prenom?: string;
ch r e
©A
}
Angular
Contenu de personne.service.ts
@Injectable({
H I ©
EL
providedIn: ’root’
})
export class PersonneService {
O U
f E LM
url: string = "http://localhost:8000/ws/personnes";
ch r e
©A
constructor(private http: HttpClient) { }
getAll() {
return this.http.get<Array<Personne>>(this.url);
}
addPerson(p: Personne) {
return this.http.post(this.url, p);
}
}
Angular
Contenu de personne.component.html
">
O U
Prénom : <input type=text name=prenom [(ngModel)]=personne.prenom required #prenom="ngModel
LM
</div>
<div [hidden]="prenom.valid || prenom.pristine">
Le prénom est obligatoire
</div>
r e f E
<div>
ch
©A
<button [disabled]=!monForm.valid>
ajouter
</button>
</div>
</form>
Angular
Contenu de personne.component.css
.ng-invalid:not(form){ H I ©
border-left: 5px solid red;
UEL
O
}
.ng-valid:not(form){
f E LM
ch
border-left: 5px solid green;r e
}
©A
Contenu de personne.component.ts
// les imports
@Component({
selector: ’app-personne’,
templateUrl: ’./personne.component.html’,
styleUrls: [’./personne.component.css’]
})
export class PersonneComponent implements OnInit {
personne: Personne = {};
H I ©
EL
personnes: Array <Personne> = [];
U
constructor(private personneService: PersonneService) { }
O
LM
ngOnInit() {
this.personneService.getAll().subscribe(res => {
this.personnes = res;
r e f E
ch
});
©A
}
ajouterPersonne() {
this.personneService.addPerson(this.personne).subscribe(res => {
this.personneService.getAll().subscribe(result => {
this.personnes = result;
});
});
}
}
Angular
Exercice
Pour chaque personne, ajoutez
H I ©
U EL la personne
un bouton supprimer qui permet de supprimer
associée de la base de données O
L M
un lien modifier qui
r e E
f d’afficher les données relatives à la
permet
A
personne associc h
ée dans un formulaire du composant
©
edit-personne afin de permettre la modification de ces
données.
Angular
Pour commencer
H I ©
EL
Créons une interface user : ng g i interfaces/user
U
Créons un composant authL MgOc composants/auth
: ng
r e f E
A ch
Créons un service auth : ng g s services/auth
©
Angular
Contenu de user.ts
H I ©
export interface User {
UEL
id?: number;
O
email?: string;
f ELM
password?: string;
ch r e
©A
}
Angular
Commençons par modifier le contenu de auth.service.ts en ajoutons une
méthode login qui utilise la méthode HTTP POST pour interroger le backend
import { Injectable } from ’@angular/core’;
import { HttpClient } from ’@angular/common/http’;
import { User } from ’../interfaces/user’;
H I ©
@Injectable({
providedIn: ’root’
U EL
O
LM
})
export class AuthService {
r e f E
A ch
private url = ’http://localhost:8000/authentication_token’;
©
constructor(private http: HttpClient) { }
login(user: User) {
return this.http.post(this.url, user);
}
}
Angular
Préparons le formulaire d’authentification (auth.component.html)
<h3> Authentication</h3>
<form #monForm=ngForm (ngSubmit)=login()>
<div>
Email : <input type=text name=email [(ngModel)]=user.
email required>
H I ©
</div>
U EL
O
<div>
f ELM
Mot de passe : <input type=text name=password [(ngModel
ch r e
)]=user.password required>
©A
</div>
<div>
<button>
connexion
</button>
</div>
</form>
Angular
Dans auth.component.ts, on utilise la méthode login de auth.service.ts. si on reçoit un token l’utilisateur existe
dans la base (on ajoute donc le token au localstorage)
@Component({
selector: ’app-auth’,
H I ©
EL
templateUrl: ’./auth.component.html’,
styleUrls: [’./auth.component.css’]
})
O U
LM
export class AuthComponent implements OnInit {
user: User = {};
r e f E
constructor(private authService: AuthService, private router: Router) { }
ch
ngOnInit(): void {
©A
}
login() {
this.authService.login(this.user).subscribe(res => {
if (res[’token’]) {
localStorage.setItem(’token’, res[’token’]);
this.router.navigateByUrl(’/personne’);
}
else {
this.router.navigateByUrl(’/auth’);
}
});
}
}
Angular
Modifions maintenant le contenu de personne.service.ts pour utiliser le token
@Injectable({
})
providedIn: ’root’
H I ©
EL
export class PersonneService {
f E LM
r e
constructor(private http: HttpClient) {
ch
const token = localStorage.getItem(’token’);
©A
this.headers = new HttpHeaders().set(’Authorization’, ’Bearer ’ + token);
}
getAll() {
return this.http.get(this.url, { headers: this.headers }).pipe(map(data => data[’hydra:
member’]));
}
addPerson(p: Personne) {
return this.http.post(this.url, p, { headers: this.headers });
}
}
Angular
H I ©
EL
Sans authentification, on peut accéder au composant personne
O U
f ELM
ch r e
©A
Angular
H I ©
EL
Sans authentification, on peut accéder au composant personne
O U
f ELM
ch r e
©A
Solutions
pour le premier problème : HttpInterceptor
pour le deuxième : Guard
Angular
H I ©
U EL
Commençons par créer un intercepteur auth dans services
L
ng g interceptor services/auth MO
r e f E
A ch
©
Angular
constructor() {}
ch r e
©A
intercept(request: HttpRequest<unknown>, next: HttpHandler):
Observable<HttpEvent<unknown>> {
return next.handle(request);
}
}
Angular
Déclarons l’intercepteur dans app.module.ts
©
import { AppRoutingModule } from ’./app-routing.module’;
import { AppComponent } from ’./app.component’;
H I
EL
import { PersonneComponent } from ’./composants/personne/personne.component’;
import { AuthComponent } from ’./composants/auth/auth.component’;
import {
U
AuthInterceptor } from ’./services/auth.interceptor’;
O
LM
@NgModule({
declarations: [
AppComponent,
r e f E
ch
PersonneComponent,
AuthComponent
©A
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule
],
providers: [{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }],
bootstrap: [AppComponent]
})
export class AppModule { }
Demandons à l’intercepteur de modifier toutes les requêtes en ajoutant le token sauf pour
celle qui demande le jeton (à l’authentification)
import { Injectable } from ’@angular/core’;
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from ’
@angular/common/http’;
import { Observable } from ’rxjs’;
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
H I ©
constructor() { }
U EL
O
f
Observable<HttpEvent<unknown>> {E LM
intercept(request: HttpRequest<unknown>, next: HttpHandler):
ch r e
if (request.url !== ’http://localhost:8000/authentication_token’) {
©A
const token = localStorage.getItem(’token’);
request = request.clone({
setHeaders: {
Authorization: ’Bearer ’ + token
}
});
}
return next.handle(request);
}
}
H & H: Research and Training 21 / 30
HttpInterceptor
@Injectable({
providedIn: ’root’
})
H I ©
EL
export class PersonneService {
O U
LM
private url = ’http://localhost:8000/ws/personnes’;
e f E
constructor(private http: HttpClient) { }
r
ch
©A
getAll() {
return this.http.get(this.url).pipe(map(data => data[’hydra:member’
]));
}
addPerson(p: Personne) {
return this.http.post(this.url, p);
}
}
Angular
Angular
Angular
Angular
Contenu de 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
}
}
Contenu de 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
}
}
La méthode canActivate ne fait aucun contrôle car elle retourne toujours true
Angular
Modifions le contenu de auth.guard.ts pour rediriger vers la page d’authentification s’il n’y a pas de jeton en session
@Injectable({
})
providedIn: ’root’
H I ©
EL
export class AuthGuard implements CanActivate {
return true;
}
else {
this.router.navigateByUrl(’/auth’);
return false;
}
}
UEL
const routes: Routes = [
O
LM
{ path: ’auth’, component: AuthComponent },
canActivate: [AuthGuard] },
r e E
{ path: ’editPersonne/:id’, component: EditPersonneComponent,
f
ch
{ path: ’personne’, component: PersonneComponent, canActivate: [
];
AuthGuard] },
©A
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Angular
©
import { EditPersonneComponent } from ’./composants/edit-personne/edit-personne.component’;
import { AuthComponent } from ’./composants/auth/auth.component’;
H I
EL
import { AuthGuard } from ’./services/auth.guard’;
O U
LM
{ path: ’auth’, component: AuthComponent },
{
e f E
path: ’’, canActivate: [AuthGuard], children: [
r
ch
{ path: ’editPersonne/:id’, component: EditPersonneComponent },
{ path: ’personne’, component: PersonneComponent }
©A
]}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Angular
Angular
Exercice
Dans le composant app-component, on veut afficher H I ©
UEL
O
un bouton déconnexion si un jeton est stocké dans le
WebStorage
f E LM
r e
ch qui redirige vers la page d’authentification
un lien connexion
sinon. © A