Introduction
HttpInterceptors are use to handle and intercpts the HttpRequest and HttpResponse.
In this article we will try to use the HttpInterceptors for the following reasons,
- Creating an Error Interceptor.
- Creating JSON Web Tokens (JWT)interceptor.
- Creating a Fake-Backend Service with Interceptor.
Let’s create an application(called as Event Management) which will demonstrate the use of these Interceptors.
Application will have the following functionalities,
- Register of user
- Login
- Authentication of user
- Events list
- Paid (Members) event list.
- AuthGuard for routing.
Let’s create an application.
ng new AuthApp
Create below components with Angular CLI command,
- Register ( ng g c register )
- Login
- Logout
- Events
- Paid-events
Create folders
- _guards ( to keep the auth guard file )
- _helpers ( To keep the Interceptors )
- _model ( to keep the models )
- _services ( To keep the services )
- Create class user inside _model directory.
- export class User {
- id: number;
- username: string;
- password: string;
- firstName: string;
- lastName: string;
- isAdmin: boolean;
- token: string;
- }
Add auth.service.ts through command inside _services directory,
- import { Injectable } from '@angular/core';
- import { HttpClient } from '@angular/common/http';
- import { map } from 'rxjs/operators';
- import { Observable, BehaviorSubject } from 'rxjs';
- import { User } from '../_model/user';
- @Injectable({
- providedIn: 'root'
- })
- export class AuthService {
- private currentUserSubject: BehaviorSubject<User>;
- public currentUser: Observable<User>;
- private _loginUrl = "api/login";
- private _registerUrl = "api/register";
- constructor(private http: HttpClient) {
- this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(sessionStorage.getItem('currentUser')));
- this.currentUser = this.currentUserSubject.asObservable();
- }
- public get currentUserValue(): User {
- return this.currentUserSubject.value;
- }
- getAuthToken(){
- return "TOKEN-001001010100111";
- }
- registerUser(user) {
- return this.http.post<any>(this._registerUrl, user);
- }
- login(user) {
- return this.http.post<any>(this._loginUrl, user);
- }
- authenticate(loginData) {
- return this.http.post<any>("http://localhost:4200/api/login", loginData)
- .pipe(map(user => {
- // login successful if there's a jwt token in the response
- if (user && user.token) {
- // store user details and jwt token in local storage to keep user logged in between page refreshes
- sessionStorage.setItem('currentUser', JSON.stringify(user));
- this.currentUserSubject.next(user);
- }
- return user;
- }));
- }
- logout() {
- // remove user from local storage to log user out
- sessionStorage.removeItem('currentUser');
- this.currentUserSubject.next(null);
- }
- }
Create event.service.ts through command inside _services directory,
- import { Injectable } from '@angular/core';
- import { HttpClient } from '@angular/common/http';
- @Injectable({
- providedIn: 'root'
- })
- export class EventService {
- private _eventsUrl = "api/events";
- private _paidEventsUrl = "api/paidEvents";
- constructor(private http: HttpClient) { }
- getEvents() {
- return this.http.get<any>(this._eventsUrl);
- }
- getPaidEvents() {
- return this.http.get<any>(this._paidEventsUrl);
- }
- }
Create file auth.guard.ts in _guard directory and add the below contents,
- import { Injectable } from '@angular/core';
- import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
- import { AuthService } from '../_services/auth.service';
- @Injectable({ providedIn: 'root' })
- export class AuthGuard implements CanActivate {
- constructor(
- private router: Router,
- private authenticationService: AuthService
- ) {}
- canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
- console.log("CanActivate method called from class AuthGuard..");
- const currentUser = this.authenticationService.currentUserValue;
- if (currentUser) {
- this.router.navigate(['/paidevents'], { queryParams: { returnUrl: state.url }});
- // authorised so return true
- return true;
- }
- // not logged in so redirect to login page with the return url
- this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
- return false;
- }
- }
Create error.interceptors.ts in _helpers directory,
- import { Injectable } from '@angular/core';
- import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
- import { Observable, throwError } from 'rxjs';
- import { catchError } from 'rxjs/operators';
- import { AuthService } from '../_services/auth.service';
- import { Router } from '@angular/router';
- @Injectable()
- export class ErrorInterceptor implements HttpInterceptor {
- constructor(private authenticationService: AuthService, private router: Router) { }
- intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
- return next.handle(request).pipe(catchError(err => {
- if (err.status === 401) {
- this.authenticationService.logout();
- this.router.navigate(['/login']);
- }
- const error = err.error.message || err.statusText;
- return throwError(error);
- }))
- }
- }
Create jwt.interceptor.ts in _helpers directory.
- import { Injectable } from '@angular/core';
- import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
- import { Observable } from 'rxjs';
- import { AuthService } from '../_services/auth.service';
- @Injectable()
- export class JwtInterceptor implements HttpInterceptor {
- constructor(private authenticationService: AuthService) { }
- intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
- console.log("Intercept method called from JWTInterceptor..");
- // add authorization header with jwt token if available
- let currentUser = this.authenticationService.currentUserValue;
- if (currentUser && currentUser.token) {
- request = request.clone({
- setHeaders: {
- Authorization: `Bearer ${currentUser.token}`,
- admin: "Irshad",
- Host: "localhost://3400"
- }
- });
- }
- return next.handle(request);
- }
- }
Create fake-backend-intercepter.provider.ts in _helpers directory,
- import { Injectable } from '@angular/core';
- import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';
- import { Observable, of, throwError } from 'rxjs';
- import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
- import * as jwt_decode from 'jwt-decode';
- // array in local storage for registered users
- let users = JSON.parse(localStorage.getItem('users')) || [];
- @Injectable()
- export class FakeBackendInterceptor implements HttpInterceptor {
- constructor(){}
- intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
- // Token for admin user
- const adminToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJ1c2VybmFtZSI6ImFkbWluIiwiZmlyc3ROYW1lIjoiTW9oYW1tYWQiLCJsYXN0TmFtZSI6Iklyc2hhZCJ9.apXr_qMJrzvYczZbfW23UfJdzmMaaCA8d7Njm8tN9wI";
- // Token for non-admin users
- const userToken = "fake-jwt-token";
- const { url, method, headers, body } = request;
- return of(null)
- .pipe(mergeMap(handleRoute))
- .pipe(materialize())
- .pipe(delay(500))
- .pipe(dematerialize());
- function handleRoute() {
- switch (true) {
- case url.endsWith('/api/login') && method === 'POST':
- return authenticate();
- case url.endsWith('api/register') && method === 'POST':
- return register();
- case url.endsWith('/users') && method === 'GET':
- return getUsers();
- case url.endsWith('/events') && method === 'GET':
- return getEvents();
- case url.endsWith('/paidEvents') && method === 'GET':
- return getPaidEvents();
- case url.match(/\/users\/\d+$/) && method === 'DELETE':
- return deleteUser();
- default:
- return next.handle(request);
- }
- }
- function authenticate() {
- const { username, password } = body;
- if(username=='admin' && password=='1'){
- var admin = jwt_decode(adminToken);
- admin.isAdmin = true;
- admin.token = adminToken;
- return ok(admin);
- }
- const user = users.find(x => x.username === username && x.password === password);
- if (!user) return error('Username or password is incorrect');
- return ok({
- id: user.id,
- username: user.username,
- firstName: user.firstName,
- lastName: user.lastName,
- isAdmin: false,
- token: userToken
- })
- }
- function register() {
- const user = body
- if (users.find(x => x.username === user.username)) {
- return error('Username "' + user.username + '" is already taken');
- }
- user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
- user.isAdmin = false;
- users.push(user);
- localStorage.setItem('users', JSON.stringify(users));
- return ok('Successfully created');
- }
- function getUsers() {
- if (!isLoggedIn()) return unauthorized();
- return ok(users);
- }
- function deleteUser() {
- if (!isLoggedIn()) return unauthorized();
- users = users.filter(x => x.id !== idFromUrl());
- localStorage.setItem('users', JSON.stringify(users));
- return ok();
- }
- function ok(body?) {
- return of(new HttpResponse({ status: 200, body }))
- }
- function error(message) {
- return throwError({ error: { message } });
- }
- function unauthorized() {
- return throwError({ status: 401, error: { message: 'Unauthorised' } });
- }
- function isLoggedIn() {
- return headers.get('Authorization') === 'Bearer ' + userToken || headers.get('Authorization') === 'Bearer '+ adminToken;
- }
- function getEvents() {
- return ok(events);
- }
- function getPaidEvents() {
- if (!isLoggedIn()) return unauthorized();
- return ok(paidEvents);
- }
- function idFromUrl() {
- const urlParts = url.split('/');
- return parseInt(urlParts[urlParts.length - 1]);
- }
- }
- }
- let events = [
- {
- "id": "1",
- "name": "event1",
- "place": "place1",
- "date": "date1"
- },
- {
- "id": "2",
- "name": "event3",
- "place": "place2",
- "date": "date2"
- },
- {
- "id": "3",
- "name": "event3",
- "place": "place3",
- "date": "date3"
- },
- {
- "id": "4",
- "name": "event4",
- "place": "place4",
- "date": "date4"
- },
- {
- "id": "5",
- "name": "event5",
- "place": "place5",
- "date": "date5"
- }
- ];
- let paidEvents = [
- {
- "id": "1",
- "name": "paidEvent1",
- "place": "place1",
- "date": "date1"
- },
- {
- "id": "2",
- "name": "paidEvent3",
- "place": "place2",
- "date": "date2"
- },
- {
- "id": "3",
- "name": "paidEvent3",
- "place": "place3",
- "date": "date3"
- },
- {
- "id": "4",
- "name": "paidEvent4",
- "place": "place4",
- "date": "date4"
- },
- {
- "id": "5",
- "name": "paidEvent5",
- "place": "place5",
- "date": "date5"
- }
- ];
- export const fakeBackendProvider = {
- // use fake backend in place of Http service for backend-less development
- provide: HTTP_INTERCEPTORS,
- useClass: FakeBackendInterceptor,
- multi: true
- };
Create app-routing.module.ts
- import { NgModule } from '@angular/core';
- import { Routes, RouterModule } from '@angular/router';
- import { EventsComponent } from './events/events.component';
- import { PaidEventsComponent } from './paid-events/paid-events.component';
- import { LoginComponent } from './login/login.component';
- import { RegisterComponent } from './register/register.component';
- import { AuthGuard } from './_guards/auth.guard';
- const routes: Routes = [
- {
- path: '',
- component: EventsComponent,
- canActivate: [AuthGuard]
- },
- {
- path: 'events',
- component: EventsComponent,
- },
- {
- path: 'paidevents',
- component: PaidEventsComponent
- },
- {
- path: 'login',
- component: LoginComponent
- },
- {
- path: 'register',
- component: RegisterComponent
- }
- ];
- @NgModule({
- imports: [RouterModule.forRoot(routes)],
- exports: [RouterModule]
- })
- export class AppRoutingModule { }
Let’s start with component html and ts files.
Open login.component.ts and add the below contents,
- import { Component, OnInit } from '@angular/core';
- import { AuthService } from '../_services/auth.service';
- import { Router } from '@angular/router';
- @Component({
- selector: 'app-login',
- templateUrl: './login.component.html',
- styleUrls: ['./login.component.css']
- })
- export class LoginComponent implements OnInit {
- loginData = { username: '', password: ''};
- constructor(private _authservice: AuthService, private router: Router) {
- // redirect to paidEvents if already logged in
- if (this._authservice.currentUserValue) {
- this.router.navigate(['/paidevents']);
- }
- }
- ngOnInit(): void {
- }
- login() {
- console.log(this.loginData);
- this._authservice.authenticate(this.loginData).subscribe(
- data => {
- console.log("loggedin : ", data );
- this.router.navigate(['/paidevents'], { queryParams: { }});
- },
- error => {
- console.log("erorr: ", error);
- }
- );
- console.log('Logged in successfully!');
- }
- }
Open login.component.html and add the below contents,
- <div class="row pt-5">
- <div class="co-md-6 mx-auto">
- <div class="card rounded-0">
- <div class="card-header">
- <h3 class="mb-0">Login</h3>
- </div>
- <div class="card-body">
- <form class="form">
- <div class="form-group">
- <label for="">Username</label>
- <input [(ngModel)]="loginData.username" name="username" type="text" class="form-control rounded-0" required>
- </div>
- <div class="form-group">
- <label for="">Password</label>
- <input [(ngModel)]="loginData.password" name="password" type="text" class="form-control rounded-0" required>
- </div>
- <a routerLink="/register" class="btn btn-primary float-left">Register</a>
- <button (click)="login()" type="button" class="btn btn-primary float-right">Login</button>
- </form>
- </div>
- </div>
- </div>
- </div>
Open register.component.ts and add the below contents,
- import { Component, OnInit } from '@angular/core';
- import { AuthService } from '../_services/auth.service';
- import { User } from '../_model/user';
- import { Router } from '@angular/router';
- import { Subscription } from 'rxjs';
- @Component({
- selector: 'app-register',
- host: { '[@slideInOutAnimation]': '' },
- templateUrl: './register.component.html',
- styleUrls: ['./register.component.css']
- })
- export class RegisterComponent implements OnInit {
- component: any;
- subscription: Subscription;
- registerResult: number = 0;
- registerUserData = new User();
- constructor(private _authservice: AuthService, private router: Router) {
- // redirect to home if already logged in
- if (this._authservice.currentUserValue) {
- this.router.navigate(['/paidevents']);
- }
- }
- ngOnInit(): void {
- this.registerUserData.username
- = this.registerUserData.firstName
- = this.registerUserData.lastName
- = this.registerUserData.password
- = ""
- }
- Register(user){
- console.log(user);
- this._authservice.registerUser(user).subscribe(data=>
- {
- console.log("login Details:", data);
- this.router.navigate(['/login'], { queryParams: { }});
- },
- error => {
- console.log("Error: ", error);
- },
- ()=>{
- console.log("login process complete!");
- });
- console.log('Logged in!');
- }
- }
Open register.component.html and add the below contents,
- <div class="row pt-5">
- <div class="co-md-6 mx-auto">
- <div class="card rounded-0">
- <div class="card-header">
- <h3 class="mb-0">Register</h3>
- </div>
- <div class="card-body">
- <form class="form" #newUserForm="ngForm" (ngSubmit)="Register(newUserForm.value)">
- <div class="form-group">
- <label for="">Username</label>
- <input [(ngModel)]="registerUserData.username" name="username" type="text" class="form-control rounded-0" required>
- </div>
- <div class="form-group">
- <label for="">First Name</label>
- <input [(ngModel)]="registerUserData.firstName" name="firstName" type="text" class="form-control rounded-0" required>
- </div>
- <div class="form-group">
- <label for="">Last Name</label>
- <input [(ngModel)]="registerUserData.lastName" name="lastName" type="text" class="form-control rounded-0" required>
- </div>
- <div class="form-group">
- <label for="">Password</label>
- <input [(ngModel)]="registerUserData.password" name="password" type="password" class="form-control rounded-0" required>
- </div>
- <a routerLink="/login" class="btn btn-primary float-left">Login</a>
- <button type="submit" class="btn btn-primary float-right">Register</button>
- </form>
- </div>
- </div>
- </div>
- </div>
Open events.component.ts and add the below contents,
- import { Component, OnInit } from '@angular/core';
- import { EventService } from '../_services/event.service';
- @Component({
- selector: 'app-events',
- templateUrl: './events.component.html',
- styleUrls: ['./events.component.css']
- })
- export class EventsComponent implements OnInit {
- public events: any[];
- constructor(private _eventService: EventService) { }
- getAllEvents(){
- this._eventService.getEvents().subscribe(
- data => this.events = data,
- error => console.log('Error in getting event list ', error),
- () => {console.log('success to get event list...');
- });
- }
- ngOnInit(): void {
- this.getAllEvents();
- }
- }
Open events.component.html and add the below contents,
- <h2>Events Details:</h2>
- <table class="table">
- <thead>
- <tr><th>Id</th><th>Name</th><th>Place</th><th>Date</th></tr>
- </thead>
- <tbody>
- <tr *ngFor="let event of events, index as i">
- <td>{{event.id}}</td>
- <td>{{event.name}}</td>
- <td>{{event.place}}</td>
- <td>{{event.date}}</td>
- </tr>
- </tbody>
- </table>
Open paid-events.component.ts and add the below contents,
- import { Component, OnInit } from '@angular/core';
- import { AuthService } from '../_services/auth.service';
- import { EventService } from '../_services/event.service';
- @Component({
- selector: 'app-paid-events',
- templateUrl: './paid-events.component.html',
- styleUrls: ['./paid-events.component.css']
- })
- export class PaidEventsComponent implements OnInit {
- public events: any[];
- constructor(private _eventService: EventService) { }
- getAllEvents(){
- this._eventService.getPaidEvents().subscribe(
- data => this.events = data,
- error => console.log('Error in getting event list'),
- () => {console.log('success to get event list...');
- });
- }
- ngOnInit(): void {
- this.getAllEvents();
- }
- }
Open paid-events.component.html and add the below contents,
- <header></header>
- <hr>
- <table class="table">
- <thead>
- <tr><th>Id</th><th>Name</th><th>Place</th><th>Date</th></tr>
- </thead>
- <tbody>
- <tr *ngFor="let event of events, index as i">
- <td>{{event.id}}</td>
- <td>{{event.name}}</td>
- <td>{{event.place}}</td>
- <td>{{event.date}}</td>
- </tr>
- </tbody>
- </table>
Open app.module.ts and be sure that it contains the below contents,
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule } from '@angular/core';
- import { FormsModule } from '@angular/forms';
- import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
- import { AppRoutingModule } from './app-routing.module';
- import { AppComponent } from './app.component';
- import { RegisterComponent } from './register/register.component';
- import { LoginComponent } from './login/login.component';
- import { EventsComponent } from './events/events.component';
- import { PaidEventsComponent } from './paid-events/paid-events.component';
- import { fakeBackendProvider } from './_helpers/fake-backend-intercepter.provider';
- import { JwtInterceptor } from './_helpers/jwt.interceptor';
- import { ErrorInterceptor } from './_helpers/error.interceptor';
- import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
- import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
- @NgModule({
- declarations: [
- AppComponent,
- RegisterComponent,
- LoginComponent,
- EventsComponent,
- PaidEventsComponent
- ],
- imports: [
- BrowserModule,
- FormsModule,
- HttpClientModule,
- AppRoutingModule,
- BrowserAnimationsModule,
- NgbModule
- ],
- providers: [
- { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
- { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
- fakeBackendProvider
- ],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
Open app.component.ts and add the below contents,
- import { Component } from '@angular/core';
- import { AuthService } from './_services/auth.service';
- import { Router } from '@angular/router';
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
- export class AppComponent {
- constructor(private _authservice: AuthService, private router: Router){
- console.log(_authservice);
- }
- isLoggedIn(){
- return this._authservice.currentUserValue;
- }
- logout()
- {
- this._authservice.logout();
- this.router.navigate(['/login']);
- }
- title = 'AuthApp';
- }
Open app.component.html and add the below contents,
- <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
- <a class="navbar-brand" href="#">EMS</a>
- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
- <span class="navbar-toggler-icon"></span>
- </button>
- <div class="collapse navbar-collapse" id="navbarSupportedContent">
- <ul class="navbar-nav mr-auto">
- <li class="nav-item active">
- <a class="nav-link" routerLink="/events" routerLinkActive="active">Events<span class="sr-only">(current)</span></a>
- </li>
- <li class="nav-item" *ngIf="isLoggedIn()">
- <a class="nav-link" routerLink="/paidevents" routerLinkActive="active">Members</a>
- </li>
- <li class="nav-item" *ngIf="!isLoggedIn()">
- <a class="nav-link" routerLink="/login" routerLinkActive="active">Login</a>
- </li>
- <li class="nav-item" *ngIf="!isLoggedIn()">
- <a class="nav-link" routerLink="/register" routerLinkActive="active">Register</a>
- </li>
- <li class="nav-item" *ngIf="isLoggedIn()" (click)="logout()">
- <a class="nav-link" routerLink="/register" routerLinkActive="active">Logout</a>
- </li>
- </ul>
- </div>
- </nav>
- <div class="container">
- <router-outlet></router-outlet>
- </div>
Your directory structure will be as below,

Run the application

Join the conversation! Your thoughts help the community grow.