Authentication With Route Guards In Angular 5 Single Page Application

Angular comes with many built-in features which can be used to achieve things like authentication and authorization. Route Guards are one of them. Let’s see how we can achieve this.

What are Route Guards?

Being web application developers, we are aware how a Server checks the permissions for the user on the navigation and returns the result telling whether a user can access the resource or not. In the same way, we need to achieve this on client-side. Route Guards are the solution for that. We can use the route guards to control whether the user can navigate the route or not.

Guard Types

There are 5 types of Route Guards we use in Angular.

  1. CanActivate
    This helps to decide whether the route can be activated or not.
  1. CanActivateChild
    This helps to decide whether child routes can be activated or not.
  1. CanDeactivate
    This helps to decide whether the route can be deactivated or not. Generally, this is used to warn a user if they are navigating from the component.
  1. Resolve
    This performs route data retrieval before any activation of the route.
  1. CanLoad
    Checks to see if the user can navigate to the module which is lazily loaded.

Before implementing the route guards in the application, let’s see the structure of the module which we will be using in this article.

ComponentRoute Guard Applied
HomeNone
AdminCanActivate Route Guard
MerchantCanDeactivateRouteGuard
CustomerCanActivateChildRouteGuard

The above table will give you a basic idea of how we are going to apply the guards on the Routes. The Home component will be open to all and admin will be activated. If the user has some access, then there will be a merchant which will be used with the candeactiveRouteGuard and customer which will have the CanActivateChildRouteGuard.

Before starting to implement the Guards, let's have some basic information about route guards.

  • Guards are always implemented as service that needs to be provided so we always make them @Injectable while creation.
  • Guards always return true or false telling you if access is allowed or not
  • Guards can also return the Observables or Promises which can resolve into the Boolean value finally and will be returned.
  • Every Route guard must be imported to the application or Root Module
  • As the Route guards are services they must be registered in the Providers section of the Application module.

 Before implementing the Route Guard, we need to add the component and add the routing in our application. For that, let's add 6 components, namely Home, Admin, Customer, Merchant and two child components named EditCustomer and AddCustomer, which will be child components of the Customer section.

The next step is to configure the routing in the application. Below is our Routing file.

  1. import {Routes} from '@angular/router';    
  2. import {CustomerComponent} from './customer/customer.component'  
  3. import {AdminComponent} from './admin/admin.component'  
  4. import {MerchantComponent} from './merchant/merchant.component'  
  5. import {HomeComponent} from './home/home.component'  
  6. import {AddCustomerComponent} from './add-customer/add-customer.component'  
  7. import {EditCustomerComponent} from './edit-customer/edit-customer.component'  
  8. export const Approutes: Routes =   
  9.     [    
  10.     { path: '', component: HomeComponent},    
  11.     { path: 'Home', component: HomeComponent},    
  12.     { path: 'merchant', component: MerchantComponent },    
  13.     { path: 'admin', component: AdminComponent } ,   
  14.     { path:'customer',component:CustomerComponent                              ,children:[{path:'customeredit',component:EditCustomerComponent},  
  15. {path:'customeradd',component:AddCustomerComponent}   
  16.      ]}]   

Now we are ready to implement our Route Guards

Implementing CanActivate Route Guard

Generally, in our application, we have a need where we want to check if the user is logged in or not. In that case, we can decide if we want to activate that route for that user or not.

Angular provides CanActivate Route for that. 

Let’s see how we can implement this guard in the application. For this, let's add the Route guard in the application. We can use the Angular CLI command

ng g g [guard name]

We can see the snippet for the CanActivate Route Guard as follows.

  1. import { Injectable } from '@angular/core';  
  2. import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot,Router } from '@angular/router';  
  3. import { Observable } from 'rxjs/Observable';  
  4. @Injectable()  
  5. export class AuthGuardGuard implements CanActivate   
  6. {  
  7.   constructor(private router:Router) {}  
  8. canActivate(  next: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean  
  9.      {  
  10.        alert("Unauthorized Access,Redirecting to Home");  
  11.        this.router.navigate(['Home']);  
  12.         return false;  
  13.      }  
  14. }  

Code description

We have added one simple @Injectable class, AuthGuardGuard which will implement the interface CanActivate.

Before that, we need to import some of the packages in our case they are already implemented by the CLI.

  1. import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot,Router } from '@angular/router';  

When implementing the CanActivate Interface it will be implemented and it will implement the method

  1. canActivate(  next: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<boolean> |   
  2. Promise<boolean> | boolean  

As we can see this method can return the Observable or Promise or the Simple Boolean value.

In our case, we are using the boolean value and it will be returned whenever these route guards are activated.

For the sample, we are returning the sample which alerts the user of “Unauthorized access ” and redirects them to the Home page instead of loading the component.

One more change to do is to add these route guards to the Routes. For that, we need to modify the route configuration. We can see in the table above that we have configured the Admin component with CanActivate Guard How we can do this we need to add this line to the Routing config,

  1. {path: 'admin', component:AdminComponent,canActivate:[AuthGuardGuard] }  

So whenever the admin component will be loaded it will be redirected to the Home page telling unauthorized access.

Implementing CanActivateChild Route Guard

  1. import { Injectable } from '@angular/core';  
  2. import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';  
  3. import { Observable } from 'rxjs/Observable';  
  4. import { CanActivateChild,Router } from '@angular/router';  
  5. @Injectable()  
  6. export class ActivatechildGuard implements CanActivateChild {  
  7.   constructor(private router:Router){  
  8.   }  
  9. canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> {  
  10. console.log('redirecting home due to access Rights..');  
  11. this.router.navigate(['Home']);  
  12.     return false;  
  13. }}  

In this code snippet too, we have implemented the CanActivateChild Interface which will, in turn, give us the method canActivateChild which is implemented in this case.

Route config changes for implementing this guard is as follows,

  1. [path:'customer',component:CustomerComponent,canActivateChild:[ActivatechildGuard]  
  2. ,children:[{path:'customeredit',component:EditCustomerComponent},                      {path:'customeradd',component:AddCustomerComponent}   

Our customer component has two components attached to it, namely, add Customer and Edit customer. So, our CanActivateChild Guard will take care of that and decides whether to activate the Guard or not depending on the return value from the Guard

Implementing CanDeactivate Route Guard

Sometimes, we have a condition where we want the user to confirm if he really wants to navigate from the component. We can use CanDeactivate route guard for this.

Code snippet for this can be like below

  1. import { Injectable } from '@angular/core';  
  2. import { CanDeactivate } from '@angular/router';  
  3. import {MerchantComponent} from './merchant/merchant.component'  
  4. @Injectable()  
  5. export class CanActivateRouteGuard implements CanDeactivate<MerchantComponent> {  
  6.   canDeactivate(component: CustomerComponent): boolean {  
  7.     
  8.    return window.confirm("Ae you sure to navigate?");  
  9.   }  
  10. }  

In the above code snippet, we can see that we have implemented the Interface CanDeactivate being the generic interface we need to pass the value of the component for which we want to implement this guard in our case it is the merchant component

Route config changes for the merchant component can be like below,

  1. { path: 'merchant', component: MerchantComponent,canDeactivate:[CanActivateRouteGuard] }  

After this, whenever we load the merchant component and navigate to another component, it will ask us - Are you sure you want to navigate? and depending on that confirm box output value, it either stops or navigates to the next routes

Route Guards Parameters

ActivatedRouteSnapshot

This is the future route which will be activated when the guard condition is passed

RouterStateSnapshot

This the future router state which will be activated if the guard is passed.

To sum up we can add the Route Guards in Following ways

  1. To Restrict Access or to warn before the navigation we can use the Route Guards depending on our need.
  2. We can use the Interface canActivate,canDeactivate,canActivateChild for that purpose.
  3. Route Guards are injectable classes which can accept service dependency which can further be called and determine if we want to load the Route or not.

Hope you understand how we can achieve the authentication with Angular in the single page application and the concept of the Route Guards. To understand the routing and navigation in Angular you can follow the below articles.

Git hub repository for this article can be found here.

References

  1. https://angular.io/
  2. https://rangle.io/