0% found this document useful (0 votes)
62 views

Angular JWT User Authentication-Version2

The document describes the process of setting up user authentication with Angular and JWT (JSON Web Tokens). It involves generating Angular modules, components, classes and services for user registration, login, authentication guard and logout. Key steps include creating a User class, AuthService for authentication functions, RegisterComponent for registration, LoginComponent for login, LogoutComponent, authentication guard and setting up routes with authentication guard. It also discusses adding refresh tokens to get a new access token and keep the user logged in.

Uploaded by

mohamedtrigui6
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
62 views

Angular JWT User Authentication-Version2

The document describes the process of setting up user authentication with Angular and JWT (JSON Web Tokens). It involves generating Angular modules, components, classes and services for user registration, login, authentication guard and logout. Key steps include creating a User class, AuthService for authentication functions, RegisterComponent for registration, LoginComponent for login, LogoutComponent, authentication guard and setting up routes with authentication guard. It also discusses adding refresh tokens to get a new access token and keep the user logged in.

Uploaded by

mohamedtrigui6
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Angular JWT User Authentication

Login
Créer le module

ng generate module authentification --routing

Créer le composant

ng g c authentification/login

Créer la classe

ng generate class authentification/user

export class User {


_id:object;
email:string;
password:string;
firstname:string;
lastname:string;
}

Créer le service

ng generate service authentification/auth

import { Injectable } from '@angular/core';


import { User } from './user';
import { Observable } from 'rxjs';
import {HttpClient} from '@angular/common/http';
import { Router } from '@angular/router';

@Injectable({
providedIn: 'root'
})
export class AuthService {
private baseurl="http://localhost:3001/api/users"
constructor(private http: HttpClient, public router: Router) { }

// Sign-up
signUp(user: User): Observable<any> {

return this.http.post(this.baseurl + '/register/', user);


}
// Sign-in
signIn(user: any) {
return this.http
.post<any>(this.baseurl + "/login/" , user)
.subscribe({
next: (res:any) => {
localStorage.setItem('access_token', res.token);

},
error: (e:any) => {
console.log(e);
alert("Error !")
},
complete: () => {
this.router.navigate(['products']);
}
});
}
getToken() {
return localStorage.getItem('access_token');
}
getisLoggedIn(): boolean {
let authToken = localStorage.getItem('access_token');
return authToken !== null ? true : false;
}
doLogout() {
let removeToken = localStorage.removeItem('access_token');
if (removeToken == null) {
this.router.navigate(['login']);
}
}

 Créer le composant src>app>authentification/register


ng g c authentification/register --skip-tests
ouvrir le fichier register.component.ts

import { Component } from '@angular/core';


import { User } from '../user';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent {
constructor(private authserv:AuthService,private router:Router){}
user:User=new User()
Ajoutuser=()=>{
this.authserv.signUp(this.user).subscribe((data=>{

this.router.navigate(['login']);

}))}

Fichier register.component.html

<form (ngSubmit)="Ajoutuser()" >


<div class="mb-3">

<input type="text" class="form-control" id="email" name = "email"


placeholder="email" [(ngModel)]="user.email" >
</div>
<div class="mb-3">

<input type="text" class="form-control" id="password" name =


"password" placeholder="password" [(ngModel)]="user.password" >
</div>
<div class="mb-3">

<input type="text" class="form-control" id="firstname" name =


"firstname" placeholder="firstname" [(ngModel)]="user.firstname" >
</div>
<div class="mb-3">

<input type="text" class="form-control" id="lastname" name =


"lastname" placeholder="lastname" [(ngModel)]="user.lastname" >
</div>

<div>
<button type="submit" class="btn btn-success">Enregistrer</button>
</div>

</form>

import { NgModule } from '@angular/core';


import { CommonModule } from '@angular/common';

import { AuthentificationRoutingModule } from './authentification-


routing.module';
import { LoginComponent } from './login/login.component';
import { FormsModule } from '@angular/forms';

@NgModule({
declarations: [
LoginComponent
],
imports: [
CommonModule,
AuthentificationRoutingModule,
FormsModule,
]
})
export class AuthentificationModule { }

Fichier Authentification-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RegisterComponent } from './register/register.component';

const routes: Routes = [


{ path: 'register', component: RegisterComponent },
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AuthentificationRoutingModule { }

 Créer le composant src>app>authentification/login

ng g c authentification/login --skip-tests

import { Component } from '@angular/core';


import { AuthService } from '../auth.service';
import { Router } from '@angular/router';
import { User } from '../user';

@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
constructor(public authService: AuthService,public router: Router){}

email:string=''
password:string=''

loginUser() {
const userlogin={
email:this.email,
password:this.password
}
this.authService.signIn(userlogin);
}

<div class="form-signin w-50 m-auto">


<form (ngSubmit)="loginUser()">
<h3 class="h3 mb-3 font-weight-normal text-center">Login</h3>
<div class="mb-3">
<label>Email</label>
<div class="mb-3">

<input type="text" class="form-control" id="email" name = "email"


placeholder="email" [(ngModel)]="email" >
</div>
</div>
<div class="mb-3">
<label>Password</label>
<div class="mb-3">

<input type="text" class="form-control" id="password" name =


"password" placeholder="password" [(ngModel)]="password" >
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">Sign in</button>
</div>
</form>
</div>

import { NgModule } from '@angular/core';


import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';

const routes: Routes = [


{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AuthentificationRoutingModule { }

import { AuthentificationModule } from


'./authentification/authentification.module';

imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
ProductsModule,
AuthentificationModule
],
Logout
src >app>logout

ng g c authentification/logout --skip-tests
fichier Logout.component.ts
import { Component } from '@angular/core';
import { AuthService } from '../auth.service';

@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.css']
})
export class LogoutComponent {
constructor(public authService: AuthService) { }
ngOnInit(){
this.logout()
}
logout() {
this.authService.doLogout()
}

<div class="container d-flex flex-wrap p-3 px-md-4 mb-3 bg-white border-


bottom">
<nav class="navbar navbar-light bg-light">
<a *ngIf="this.authService.isLoggedIn" class="p-2 text-dark"
routerLink="/products">Liste des Produits</a>
<a
*ngIf="!this.authService.isLoggedIn"
class="btn btn-light text-dark me-2"
routerLinkActive="active"
routerLink="/log-in">Sign in</a
>
</nav>
<button
(click)="logout()"
*ngIf="this.authService.isLoggedIn"
type="button"
class="btn btn-default">
Logout
</button>
</div>
<div class="container mt-5">
<div class="mt-5">
<router-outlet></router-outlet>
</div>
</div>
Protected Routes avec CanActivate
ng g guard authentification/auth

import { CanActivateFn } from '@angular/router';


import {
Router
} from '@angular/router';

import { AuthService } from './auth.service';


import { inject } from '@angular/core';

export const authGuard: CanActivateFn = (route, state) => {


const authService = inject(AuthService);
const router = inject(Router);
if (authService.getisLoggedIn()!==true) {
window.alert('Access not allowed!');
router.navigate(['login']);
}

return true;
};

import { NgModule } from '@angular/core';


import { RouterModule, Routes } from '@angular/router';

import { IndexComponent } from './index/index.component';

import { AuthGuard } from '../authentification/auth.guard';

const routes: Routes = [


{ path: 'products', component: IndexComponent , canActivate: [AuthGuard] },
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProductsRoutingModule { }
Refresh Token

import { Injectable } from '@angular/core';


import { User } from './user';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import {
HttpClient,
HttpHeaders,
HttpErrorResponse,
} from '@angular/common/http';
import { Router } from '@angular/router';

@Injectable({
providedIn: 'root'
})
export class AuthService {

endpoint: string = 'https://backend-commerce-2023-jwt.vercel.app/api';

headers = new HttpHeaders().set('Content-Type', 'application/json');


currentUser = {};
constructor(private http: HttpClient, public router: Router) {}
// Sign-up
signUp(user: User): Observable<any> {
let api = `${this.endpoint}/users/register/`;
return this.http.post(api, user).pipe(catchError(this.handleError));
}
// Sign-in
signIn(user: User) {
return this.http
.post<any>(`${this.endpoint}/users/login`, user)
.subscribe({
next: (res:any) => {
localStorage.setItem('access_token', res.token);
localStorage.setItem('refresh_token', res.refreshToken);
},
error: (e:any) => {
console.log(e);
alert("Error !")
},
complete: () => {
this.router.navigate(['products']);
}
});
}
getToken() {
return localStorage.getItem('access_token');
}
get isLoggedIn(): boolean {
let authToken = localStorage.getItem('access_token');
return authToken !== null ? true : false;
}
doLogout() {
let removeToken = localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
if (removeToken == null) {
this.router.navigate(['log-in']);
}
}

// Error
handleError(error: HttpErrorResponse) {
let msg = '';
if (error.error instanceof ErrorEvent) {
// client-side error
msg = error.error.message;
} else {
// server-side error
msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(msg);
}

//refresh

refreshToken(token: string) {

const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

return this.http.post(`${this.endpoint}/users/refreshToken/`, {
refreshToken: token
}, httpOptions);
}

import { HTTP_INTERCEPTORS, HttpEvent, HttpErrorResponse } from


'@angular/common/http';
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest } from
'@angular/common/http';

import { AuthService } from "./auth.service";

import { BehaviorSubject, Observable, throwError } from 'rxjs';


import { catchError, filter, switchMap, take } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

private isRefreshing = false;


private refreshTokenSubject: BehaviorSubject<any> = new
BehaviorSubject<any>(null);

constructor(private authService: AuthService) { }


intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<Object>> {
let authReq = req;
const authToken = this.authService.getToken();
if (authToken != null) {
authReq = this.addTokenHeader(req, authToken);
}

return next.handle(authReq).pipe(catchError(error => {


if (error instanceof HttpErrorResponse && error.status === 403) {
return this.handle403Error(authReq, next);
}

return throwError(error);
}));
}

private handle403Error(request: HttpRequest<any>, next: HttpHandler) {


if (!this.isRefreshing) {
this.isRefreshing = true;
this.refreshTokenSubject.next(null);

const token = localStorage.getItem('refresh_token');


/*
nous devons appeler la fonction refreshToken()
qui utilise HttpClient pour envoyer une requête HTTP
avec rafraîchirToken dans le body.
*/
/*
L'Angular SwitchMap mappe chaque valeur de l'observable source vers un
observable interne,
s'y abonne, puis commence à en émettre les valeurs.
Il crée un nouvel observable intérieur pour chaque valeur qu'il reçoit de la
Source.
Chaque fois qu'il crée un nouvel observable interne,
il se désabonne de tous les observables internes précédemment créés.
Fondamentalement, il passe au plus récent observable en éliminant tous les
autres.
*/
if (token)
return this.authService.refreshToken(token).pipe(
switchMap((res: any) => {
this.isRefreshing = false;
localStorage.setItem('access_token', res.token);
localStorage.setItem('refresh_token', res.refreshToken);
this.refreshTokenSubject.next(res.token);

return next.handle(this.addTokenHeader(request, res.token));


}),
catchError((err) => {
this.isRefreshing = false;

this.authService.doLogout();
return throwError(err);
})
);
}

return this.refreshTokenSubject.pipe(
filter(token => token !== null),
take(1),
switchMap((token) => next.handle(this.addTokenHeader(request,
token)))
);
}

private addTokenHeader(request: HttpRequest<any>, token: string) {


return request.clone({ setHeaders: {
Authorization: "Bearer " + token
}
});
}
}

export const authInterceptorProviders = [


{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
];
Après une minute (délai d’expiration)

On voit l’erreur de code 403 qui invoque la requête de RefreshToken et génère le nouveau token. Ce
qui permet d’afficher la liste des produits avec l’autorisation du nouveau token.

You might also like