Role Based Access Control In Angular 4 Route Guards in Depth

1
21289
views

As you all know about JWT authentication and normal auth guards. They will give users permission to sign in and access required route.

Now you want to restrict certain routes or don’t want to give permission to access those routes. Here Role based authentication comes into the picture. We are going to achieve this in a while,

What is Route Guard?

Route guards make the decision by looking for a true or false return value from a class which implements the given guard interface.

There are different kind of route guards. You can modify the behaviour of the route guard based on which route guard you are going to make use of it.

  1. CanActivate
  2. CanActivateChild
  3. CanDeactivate
  4. CanLoad
  5. Resolve
    1. More of the details of above mentioned route guards can be found in the Angular docs.

      Create a Auth Service

      Create a auth.service service which which checks for validity of existing jwt token in the local storage. You can also give different name if you want!

      The code looks something like this

      import { Injectable } from '@angular/core';
      
      @Injectable()
      export class AuthService {
      
        constructor() { }
        public isAuthenticated(): boolean {
          const token = localStorage.getItem('jwt');
          if (!token) {
            console.log("Token does not exists");
            return false;
          }
          else {
            console.log("Token exists");
            return true;
          }
        }
      
      }
      

      We are not validating the token here for more security you have to validate the token sending it to the backend, if you get success in return from the backend then return true.

      Create a Role Guard Service

      Create a role-guard.service service which implements the route guard. You can also give different name if you want! This is what all we wanted to achieve as said in the article title and our major focus is going to be here.

      The code looks something like this

      import { Injectable } from '@angular/core';
      import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
      import { AuthService } from './auth.service';
      import * as decode  from 'jwt-decode';
      
      @Injectable()
      export class RoleGuardService implements CanActivate {
        constructor(public auth: AuthService, public router: Router) {}
        canActivate(route: ActivatedRouteSnapshot): boolean {
         
          let expectedRoleArray = route.data;
           expectedRoleArray = expectedRoleArray.expectedRole;
        
          const token = localStorage.getItem('jwt');
      
          // decode the token to get its payload
          const tokenPayload = decode(token);
      
          let  expectedRole = '';
      
          for(let i=0; i<expectedRoleArray.length; i++){
            if(expectedRoleArray[i]==tokenPayload.role){
              console.log("Roles Matched");
              expectedRole = tokenPayload.role;
            }
          }
       
          if (this.auth.isAuthenticated() && tokenPayload.role == expectedRole) {
            console.log("User permitted to access the route");
            return true;
          }
          return false;
      
          //this.router.navigate(['login']);
        }
      }
      

      The service injects AuthService and ActivatedRouteSnapshot rather than router itself, and It has a single method called canActivate. This method is required to implement the CanActivate interface.

      The canActivate method returns a boolean indicating whether or not navigation to a route should be allowed or not. If the user isn’t authenticated, then he/she will be redirected to some other place based on where you want them to go. like /login.

      You need to use jwt-decode to decode the token and get the payload which contains the role of user which we are going to match with the assigned permissions of all the routes.

      Activated route snap shot gives us the permissions array data from routing file or routes(If you are writing routes in separate file). We are going to loop through each permission of a route and at the same time we try to match with the JWT payload role.

      If it matches we will give the access to that particular route or else we will redirect userto some other route.

      Role Based Access Control In Angular 4 Route Guards in Depth

      Our routes looks something like this
      Note: Imported RoleGuardService with the alias name like this

      import { RoleGuardService as RoleGuard } from './role-guard.service';
      

      so don’t be confused. You can even make use of RoleGuardService name directly in the canActivate.

      
      const MAINMENU_ROUTES: Routes = [
          
          {
              path: 'allInvoices',
              component: AllinvoicesComponent,
              canActivate: [RoleGuard], 
              data: { 
                  expectedRole: ['FTH', 'FA']
                } 
          },
          {
              path: 'razorPayments',
              component: RazorpaypaymentsComponent,
              canActivate: [RoleGuard],
              data: { 
                  expectedRole: ['FTH', 'FA']
                }  
          },
        
          {
              path: 'manualPayments',
              component: ManualpaymentsComponent,
              canActivate: [RoleGuard],
              data: { 
                  expectedRole: ['FTH','FA']
                }  
          },
      
          {
              path: 'dispatchList',
              component: DispatchlistComponent,
              canActivate: [RoleGuard], 
              data: { 
                  expectedRole: ['FTH','FA','FT']
                } 
          },
      
          {
              path: 'orgregistration',
              component: OrgregistrationComponent,
              canActivate: [RoleGuard], 
              data: { 
                  expectedRole: ['FA']
                } 
          },
          {
              path: 'allorganisations',
              component: AllorganisationComponent,
              canActivate: [RoleGuard],
              data: { 
                  expectedRole: ['FTH', 'FA']
                }  
          },
          
          {
              path: 'viewallusers',
              component: ViewallusersComponent,
              canActivate: [RoleGuard], 
              data: { 
                  expectedRole: ['FTH', 'FA']
                } 
          },
          
      
      ];
      export const CONST_ROUTING = RouterModule.forRoot(MAINMENU_ROUTES);
      

      We still need to hide and show the particular routes in html file also

        <div *ngIf="showDispatches">
                  <a *ngIf="getRoleB()" [routerLinkActive]="['active']" [routerLink]="['/dispatches']">Dispatches</a>
                  <a *ngIf="getRoleC()" [routerLinkActive]="['active']" [routerLink]="['/dispatchList']">Dispatch List</a>
              </div>
      

      Our typescript file is going to looks like this

      import { Router } from '@angular/router';
      import { Component, OnInit } from '@angular/core';
      import * as decode  from 'jwt-decode';
      
      @Component({
        selector: 'app-sidebar',
        templateUrl: './sidebar.component.html',
        styleUrls: ['./sidebar.component.css']
      })
      export class SidebarComponent implements OnInit {
      constructor( private loginService: LoginService,   private router: Router) {
          const token = localStorage.getItem('jwt');
          const tokenPayload = decode(token);
          console.log("tokenPayload.role", tokenPayload.role);
          this.Role = tokenPayload.role;
         }
      
         getRoleB(){
           if(this.Role=='FA' || this.Role=='FTH'){
             return true;
           }
           else{
            return false;
           }
         }
      
         getRoleC(){
          if(this.Role=='FA' || this.Role=='FTH' || this.Role=='FT'){
            return true;
          }
          else{
           return false;
          }
        }
      }
      

      Guys is there any specific topic you want me to write blog on please post it in the comments..

      I hope it helped you. Give us appreciation in the comments

      Role Based Access Control In Angular 4 Route Guards in Depth

      Happy Coding..!