Ionic 4 and Angular 7 Tutorial: Securing Pages using Route Guard

Ionic 4 and Angular 7 Tutorial: Securing Pages using Route Guard

The comprehensive step by step tutorial on securing pages using Ionic 4 and Angular 7 Route Guard

The comprehensive step by step tutorial on securing pages using Ionic 4 and Angular 7 Route Guard

The Ionic 4 and Angular 7 app similar with the previous tutorial except add the Route Guard to securing the restricted page. The workflow diagram below shows the flow of the whole application.

Ionic 4 and Angular 7 Tutorial

Table of Contents:

  • Create a new Ionic 4 and Angular 7 App
  • Create a custom Angular 7 HttpInterceptor
  • Create Ionic 4 Angular 7 Authentication and Book Services
  • Create an Ionic 4 and Angular 7 Page for Displaying Books
  • Create the Ionic 4 and Angular 7 Pages for Login and Register
  • Secure the Guarded Book Page using Angular 7 Route Guard
  • Run and Test the Ionic 4 and Angular 7 Securing Pages using Route Guard

The following tools, frameworks, and modules are required for this tutorial:

Before going to the main steps, we assume that you have to install Node.js. Next, upgrade or install new Ionic 4 CLI by open the terminal or Node command line then type this command.

sudo npm install -g ionic

You will get the latest Ionic CLI in your terminal or command line. Check the version by type this command.

ionic --version
5.0.2

1. Create a new Ionic 4 and Angular 7 App

To create a new Ionic 4 and Angular 7 application, type this command in your terminal.

ionic start ionic4-angular7-routeguard blank --type=angular

If you see this question, just type N for because we will installing or adding Cordova later.

Integrate your new app with Cordova to target native iOS and Android? (y/N) N

After installing [NPM](https://morioh.com/topic/npm) modules and dependencies, you will see this question, just type N because we are not using it yet.

Install the free Ionic Pro SDK and connect your app? (Y/n) N

Next, go to the newly created app folder.

cd ./ionic4-angular7-routeguard

As usual, run the Ionic 4 and Angular 7 app for the first time, but before run as lab mode, type this command to install @ionic/lab.

npm install --save-dev @ionic/lab
ionic serve -l

Now, open the browser and you will the Ionic 4 and Angular 7 app with the iOS, Android, or Windowsview. If you see a normal Ionic 4 blank application, that's mean you ready to go to the next steps.

Ionic 4 and Angular 7 Tutorial

2. Create a custom Ionic 4 Angular 7 HttpInterceptor

Before creating a custom Angular 7 HttpInterceptor, create a folder under app folder.

mkdir src/app/interceptors

Next, create a file for the custom Angular 7 HttpInterceptor.

touch src/app/interceptors/token.interceptor.ts

Open and edit that file the add these imports.

import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import {
  Router
} from '@angular/router';
import { ToastController } from '@ionic/angular';

Create a class that implementing HttpInterceptor method.

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

}

Inject the required module to the constructor inside the class.

constructor(private router: Router,
  public toastController: ToastController) {}

Implement a custom Interceptor function.

intercept(request: HttpRequest, next: HttpHandler): Observable> {

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

  if (token) {
    request = request.clone({
      setHeaders: {
        'Authorization': token
      }
    });
  }

  if (!request.headers.has('Content-Type')) {
    request = request.clone({
      setHeaders: {
        'content-type': 'application/json'
      }
    });
  }

  request = request.clone({
    headers: request.headers.set('Accept', 'application/json')
  });

  return next.handle(request).pipe(
    map((event: HttpEvent) => {
      if (event instanceof HttpResponse) {
        console.log('event--->>>', event);
      }
      return event;
    }),
    catchError((error: HttpErrorResponse) => {
      if (error.status === 401) {
        if (error.error.success === false) {
          this.presentToast('Login failed');
        } else {
          this.router.navigate(['login']);
        }
      }
      return throwError(error);
    }));
}

Add function for call a toast controller.

async presentToast(msg) {
  const toast = await this.toastController.create({
    message: msg,
    duration: 2000,
    position: 'top'
  });
  toast.present();
}

Next, we have to register this custom HttpInterceptor and HttpClientModule. Open and edit src/app/app.module.ts then add this imports.

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { TokenInterceptor } from './inteceptors/token.interceptor';

Add those modules to the provider array of the @NgModule.

providers: [
  StatusBar,
  SplashScreen,
  { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
  {
    provide: HTTP_INTERCEPTORS,
    useClass: TokenInterceptor,
    multi: true
  }
],

Now, the HTTP interceptor is ready to intercept any request to the API.

3. Create Ionic 4 Angular 7 Authentication and Book Services

First, create a folder for those services under src/app/.

mkdir src/app/services

Create services or providers for authentication and book.

ionic g service services/auth
ionic g service services/book

Next, open and edit src/app/services/auth.service.ts then replace all codes with this.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

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

  apiUrl = 'http://localhost:3000/api/';
  isLoggedIn = false;
  redirectUrl: string;

  constructor(private http: HttpClient) { }

  login(data: any): Observable {
    return this.http.post(this.apiUrl + 'signin', data)
      .pipe(
        tap(_ => this.isLoggedIn = true),
        catchError(this.handleError('login', []))
      );
  }

  logout(): Observable {
    return this.http.get(this.apiUrl + 'signout')
      .pipe(
        tap(_ => this.isLoggedIn = false),
        catchError(this.handleError('logout', []))
      );
  }

  register(data: any): Observable {
    return this.http.post(this.apiUrl + 'signup', data)
      .pipe(
        tap(_ => this.log('login')),
        catchError(this.handleError('login', []))
      );
  }

  private handleError(operation = 'operation', result?: T) {
    return (error: any): Observable => {
      console.error(error); // log to console instead
      this.log(`${operation} failed: ${error.message}`);
      return of(result as T);
    };
  }

  private log(message: string) {
    console.log(message);
  }
}

Next, open and edit src/app/services/book.service then replace all codes with this.

import { Injectable } from '@angular/core';
import { Book } from '../book/book';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

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

  apiUrl = 'http://localhost:3000/api/';

  constructor(private http: HttpClient) { }

  getBooks (): Observable {
    return this.http.get(this.apiUrl + 'book')
      .pipe(
        tap(_ => this.log('fetched books')),
        catchError(this.handleError('getBooks', []))
      );
  }

  private handleError (operation = 'operation', result?: T) {
    return (error: any): Observable => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  /** Log a HeroService message with the MessageService */
  private log(message: string) {
    console.log(message);
  }
}

4. Create an Ionic 4 and Angular 7 Page for Displaying Books

Type this command to generate an Ionic 4 and Angular 7 page for the book.

ionic g page book

Create a Typescript file for handle Book object or as a model for Book object.

touch src/app/book/book.ts

Open end edit that file then replaces all codes with this.

export class Book {
  _id: number;
  isbn: string;
  title: string;
  author: number;
  publisher: Date;
  __v: number;
}

Next, open and edit src/app/book/book.page.ts then add this imports.

import { Book } from './book';
import { BookService } from '../services/book.service';
import { AuthService } from '../services/auth.service';
import { Router } from '@angular/router';

Inject all required modules to the constructor.

constructor(private bookService: BookService,
  private authService: AuthService,
  private router: Router) { }

Declare this variable before the constructor.

books: Book[];

Create a function for consuming or get a book list from the BookService.

getBooks(): void {
  this.bookService.getBooks()
    .subscribe(books => {
      console.log(books);
      this.books = books;
    });
}

Call this function from ngOnInit.

ngOnInit() {
  this.getBooks();
}

Add a function for log out the current session.

logout() {
  this.authService.logout()
    .subscribe(res => {
      console.log(res);
      localStorage.removeItem('token');
      this.router.navigate(['home']);
    });
}

Next, open and edit src/app/book/book.page.html then replace all HTML tags with this.



    List of Books











      {{b.title}}


The book page just shows the list of the book and log out button on the title bar.

5. Create the Ionic 4 and Angular 7 Pages for Login and Register

Before creating that pages, create this folder under src/app.

mkdir src/app/auth

Now, generate the Ionic 4 and Angular 7 pages.

ionic g page auth/login
ionic g page auth/register

Next, open and edit src/app/auth/login/login.page.ts then replace all codes with this.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
import { ToastController } from '@ionic/angular';

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {

  loginForm: FormGroup;

  constructor(private formBuilder: FormBuilder,
    private router: Router,
    private authService: AuthService,
    public toastController: ToastController) { }

  ngOnInit() {
    this.loginForm = this.formBuilder.group({
      'username' : [null, Validators.required],
      'password' : [null, Validators.required]
    });
  }

  onFormSubmit(form: NgForm) {
    this.authService.login(form)
      .subscribe(res => {
        if (res.token) {
          localStorage.setItem('token', res.token);
          this.router.navigate(['book']);
        }
      }, (err) => {
        console.log(err);
      });
  }

  register() {
    this.router.navigate(['register']);
  }

  async presentToast(msg) {
    const toast = await this.toastController.create({
      message: msg,
      duration: 2000,
      position: 'top'
    });
    toast.present();
  }

}

Next, open and edit src/app/auth/login/login.module.ts then add the import of ReactiveFormsModule.

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

Add that module to the @NgModule imports array.

imports: [
  CommonModule,
  FormsModule,
  IonicModule,
  ReactiveFormsModule,
  RouterModule.forChild(routes)
],

Next, open and edit src/app/auth/login/login.page.html then replace all HTML tags with this.





        Please, Sign In



          Username



          Password



          Login


          Register




Next, open and edit src/app/auth/register/register.page.ts then replace all codes with this.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
import { ToastController, AlertController } from '@ionic/angular';

@Component({
  selector: 'app-register',
  templateUrl: './register.page.html',
  styleUrls: ['./register.page.scss'],
})
export class RegisterPage implements OnInit {

  registerForm: FormGroup;

  constructor(private formBuilder: FormBuilder,
    private router: Router,
    private authService: AuthService,
    public toastController: ToastController,
    public alertController: AlertController) { }

  ngOnInit() {
    this.registerForm = this.formBuilder.group({
      'username' : [null, Validators.required],
      'password' : [null, Validators.required]
    });
  }

  onFormSubmit(form: NgForm) {
    this.authService.register(form)
      .subscribe(_ => {
        this.presentAlert('Register Successfully', 'Please login with your new username and password');
      }, (err) => {
        console.log(err);
      });
  }

  async presentToast(msg) {
    const toast = await this.toastController.create({
      message: msg,
      duration: 2000,
      position: 'top'
    });
    toast.present();
  }

  async presentAlert(header, message) {
    const alert = await this.alertController.create({
      header: header,
      message: message,
      buttons: [{
          text: 'OK',
          handler: () => {
            this.router.navigate(['login']);
          }
        }]
    });

    await alert.present();
  }

}

Next, open and edit src/app/auth/register/register.module.ts then add the import of ReactiveFormsModule.

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

Add that module to the @NgModule imports array.

imports: [
  CommonModule,
  FormsModule,
  IonicModule,
  ReactiveFormsModule,
  RouterModule.forChild(routes)
],

Open and edit src/app/auth/register/register.page.html then replace all HTML tags with this.






    Register







        Register here



          Username



          Password



          Register




6. Secure the Guarded Book Page using Angular 7 Route Guard

This is the main part of the Ionic 4 tutorial. Type this command to generate a guard configuration file.

ng generate guard auth/auth

Open and edit that file then add this Angular 7 / Typescript imports.

import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';

Next, add this implements code to the Class name.

export class AuthGuard implements CanActivate

Inject the AuthService and the Router to the constructor params.

constructor(private authService: AuthService, private router: Router) {}

Add the function for the Route Guard.

canActivate(
  next: ActivatedRouteSnapshot,
  state: RouterStateSnapshot): boolean {
  const url: string = state.url;

  return this.checkLogin(url);
}

Add the function to check the login status and redirect to the login page if it's not logged in and redirect to the Guarded page if it's logged in.

checkLogin(url: string): boolean {
  if (this.authService.isLoggedIn) { return true; }

  // Store the attempted URL for redirecting
  this.authService.redirectUrl = url;

  // Navigate to the login page with extras
  this.router.navigate(['/login']);
  return false;
}

Next, open and edit src/app/app-routing.module.ts then add this import.

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

Modify the book path, so it will look like this.

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: './home/home.module#HomePageModule' },
  { path: 'book', canActivate: [AuthGuard], loadChildren: './book/book.module#BookPageModule' },
  { path: 'login', loadChildren: './auth/login/login.module#LoginPageModule' },
  { path: 'register', loadChildren: './auth/register/register.module#RegisterPageModule' },
];

7. Run and Test the Ionic 4 and Angular 7 Securing Pages using Route Guard

Before run and the test the Ionic 4 and Angular 7 secure application, open the new terminal tab to run the MongoDB database.

mongod

In the other tab run the Node.js and Express.js secure REST API.

nodemon

In the main terminal tab run the Ionic 4 and Angular 7 application.

ionic serve -l

That it's, the Ionic 4 and Angular 7 Securing Pages using Route Guard. You can find the full source code from our GitHub.

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

Brave, Chrome, Firefox, Opera or Edge: Which is Better and Faster?

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

Ionic 5 Tutorial: Create Ionic Calculator App (Angular)

In this Ionic 5 tutorial, we will create an Ionic Calculator app (Angular) that run on Android or iOS device. We will use a dark theme for this Ionic calculator appearance, at least similar to a built-in iOS calculator app. The feature of this calculator app is a basic feature that only has basic calculation operators.

How to Build Mobile Apps with Angular, Ionic 4, and Spring Boot

Run Your Ionic App on Android. Make sure you're using Java 8. Run ionic cordova prepare android. Open platforms/android in Android Studio, upgrade Gradle if prompted. Set launchMode to singleTask in AndroidManifest.xml. Start your app using Android Studio...

Angular with ionic 4 required

Please provide me angular and ionic 4 tutorials with some examples.