Guards in Angular: Protecting Routes With canActivate

Introduction

We already discussed routing and how to implement the same in our Angular application in the routing post called Routing in Angular. We know how to import the routing module, configure routes, load them using different paths. There is a feature in routing called Guards. Guards are basically a logic or code which we want to run before we enter or load a route or leave it. 
  • We can protect routes using guards as we have the flexibility to run the code at the desired time. 
  • Angular provides us a great feature to guard our actions during navigation in our Application. We can guard things like entering a route, leaving a route, etc.
Suppose we need to show different dashboards for the different user- roles in our application. After login, we know which user has been logged in. On the basis of the user role, we will implement our Dashboard guard called dashboard.auth.guard.ts.

canActivate

If we want to execute some logic before we enter a route, we will use canActivate guard. We will have dashboard.auth.guard.ts. file which will implement the CanActivate interface. 
  • This interface will decide whether we can activate a particular route or not. To implement this interface, we have to define one function canActivate() which has two parameters.
  • The two parameters are the route as ActivatedRouteSnapshot and the state as RouterStateSnapshot
  • These arguments are provided by Angular when we will activate this guard before navigating to a route.
  •  The canActivate returns either observable or promise or a boolean if our guard contains logic purely for the client-side. No server logic is involved in some guards.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../auth/auth.service';
import { Router } from '@angular/router';
import { AppConstants } from '../../app.constants';

@Injectable()
export class DashboardAuthGuard implements CanActivate {
  constructor() { }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean
{
 }

Now we will apply the logic using AuthService which will have methods to check different user roles. If the user is Admin then we will show Admin Dashboard component define /app/admin/dashboard. If it is not App admin then we will redirect the user to the app/dashboard. This guard will return the value of type boolean. If it returns true, we will activate the specific route. Otherwise, we will not activate the same route configuration.

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

@Injectable()
export class DashboardAuthGuard implements CanActivate {

  constructor(private _router: Router,
    private _authService: AuthService) { }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable | Promise | boolean {

    if (state.url == "/app/admin/dashboard") {
      if (this._authService.isAppAdmin()) {
        return true;
      } else {
        this._router.navigate(["/app/dashboard"]);
        return false;
      }
    } else if (state.url == "/app/dashboard") {
      if (!this._authService.isAppAdmin()) {
        return true;
      } else {
        this._router.navigate(["/app/admin/dashboard"]);
        return false;
      }
    }
    return true;
  }
}

Now we will activate this guard by writing the below in routing module file. We will go to route configuration and define DashboardAuthGuard using canActivate property. As we are implementing this route configuration for feature module we have used forChild() instead of forRoot().
DashboardComponent will be loaded only when the DashboardAuthGuard file will return true. DashAuthGuard will execute before the activation of this route. 

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { DashboardAuthGuard } from '../../services/gaurds/dashboard.auth.guard';

const routes: Routes = [
  { path: '', canActivate:[DashboardAuthGuard], component: DashboardComponent },

];

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

Comments