Use Angular Route-Guards to Secure Angular Pages - By allow, deny or redirect to other page-view.

Use Angular Route-Guards to Secure Angular Pages - By allow, deny or redirect to other page-view.

It's very simple to secure Angular pages using route-guards.

A route guard is an important feature of the Angular Router that allows or denies the user access to the route pages based on some logic, based on weather user is logged in or not.

  • ROUTE-GUARDS are very much important in application having login/logout scenarios.
  • It’s commonly used to check if a user is logged in and has the authorization to access a page.
  • We can easily manage which page is allowed for logged in user and which for non-logged in users.

UNDERSTAND ROUTE GUARDS

We can add a route guard by implementing the CanActivate interface available from the @angular/router package and extends the canActivate() method which holds the logic to allow or deny access to the route.

For example, the following guard will check value of userLoggedIn and allow access to a route accordingly:
(Don't worry about the code - we'll understand everything in detail.)

class AuthGuardService implements CanActivate {
  userLoggedIn = false;

  canActivate() {
    if (this.userLoggedIn) {
    	return true;
    } else {
    	return false;
    }
  }
}

We can now protect a route with the guard using the canActivate attribute:

const routes: Routes = [
  {
    path: 'user/:id', 
    component: UserDetailComponent,
    canActivate:[AuthGuardService] 
  }
];

The above code is about "Routing of an Angular Component".
Click here 👆 to learn more about Angular-Routing.


We can apply 'Route Guards' to an authenticated area of our app, or an admin section that requires special permissions to be accessed.
In the following code sample we will see a very simple implementation of a route guard.

Create the Guard

We will create a service first, but to create a Guard we must implement the canActivate. Let's create a AuthGuardService run this command in your terminal/command-prompt:

ng g s service/AuthGuard

This command will generate two TypeScript file – look below👇

#1 Create AuthGuardService

Next, open the src/app/service/auth-guard.service.ts file and update it as follows: (I did import and use AuthService in this code👇👇 to learn more about AuthService Click here👆)

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

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate {

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

  // the Router call canActivate() method,
  // if canActivate is registered in Routes[]
  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    // here we check if user is logged in or not
    // the authService returs user object, or
    // it returns undefined/null when user is not logged in
    return new Promise((resolve, reject) => {
      this.authService.user.subscribe((user) => {
        if (!user) {
          // just return false - if user is not logged in
          return resolve(false);
        } else {
          // just return true - if user is logged in
          return resolve(true);
        }
      });
    });
  }
}

#2 Register AuthGuardService

We can now register this AuthGuardService in the Angular route definition. Open the src/app/app-routing.module.ts file and update it as follows:👇👇
(feel free to change value of 'path' and 'component' accordingly)

const routes: Routes = [
  {
    path: 'user/:id', 
    component: UserDetailComponent,
    canActivate:[AuthGuardService] 
  },
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [AuthGuardService]
  }
];
Note: the security doesn’t make sense on the client side. Rather we use route guards (or any other mechanisms) are all UX features, as we prevent the user from entering an area where he is not allowed to enter. But, the final security checks should always done at the server side.

Blocking is not enough

Just returning true or false is actually not enough. We need to tell the user what happened, why they not allowed to enter into the page. Either by displaying some notification or most often by redirecting to some other page view.

We can do that by injecting the router into the AuthGuard and redirect to other page view. See this: 👇👇

#3 Modifying AuthGuardService

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

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate {
  // declare a variable 'routeURL'
  // to keep track of current active route
  routeURL: string;

  constructor(private authService: AuthService, private router: Router) { 
    // initialize 'routeURL' with current route URL
    this.routeURL = this.router.url;
  }

  // the Router call canActivate() method,
  // if canActivate is registered in Routes[]
  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    // here we check if user is logged in or not
    // the authService returs user object, or
    // it returns undefined/null when user is not logged in
    
    // SINCE OUR 'authService.user' IS OF TYPE 'Observable'
    // WE MUST USE 'subscribe' TO GET VALUE OF 'user'
    return new Promise((resolve, reject) => {
      this.authService.user.subscribe((user) => {
        // check if user is not loggedIn(!user) 
        // and routeURL !== '/login'
        if (!user && this.routeURL !== '/login') {
          // assign '/login' in 'routeURL' to 
          // avoid get into infinite loop
          this.routeURL = '/login';
          // when the user is not logged in,
          // instead of just returning false
          // inject router and redirect to '/login' or any other view
          this.router.navigate(['/login'], {
            // note: this queryParams returns the current URL
            // that we can have in 'return' parameter,
            // so when the '/login' page opens,
            // this param tell us from where it comes
            // read-more to understand better👇👇
            queryParams: {
              return: state.url
            }
          });
          return resolve(false);
        } else {
          // re-assign current route URL to 'routeURL' 
          // when the user is logged in
          this.routeURL = this.router.url;
          // just return true - if user is logged in
          return resolve(true);
        }
      });
    });
  }
}

(Learn more about Use of Async-Pipe to manage Observable Subscriptions and Prevent Memory Leaks –  Click here👆)

  • Once we attach this guard to a route, the canActivate() method will fire before the route is activated, means before it opens the actual path or before it loads actual component.
const routes: Routes = [
  {
    path: 'user/:id', 
    component: UserDetailComponent,
    canActivate:[AuthGuardService] 
  }
];
  • The logic will first check if the user is valid, and if not it will navigate to the login route.
  • Note it also grabs the current URL and sets is as a query parameter, so it would be something like /login?return=%2Fusers%2Fabc123 (the URL is encoded). This is the case when we are trying to access user like this: /users/abc123 and the canActivate detects it unauthorized user.

Conclusion

#1) Create AuthGuardService
#2) Register AuthGuardService
#3) Modifying AuthGuardService


Done! 🤩 It’s that simple to secure pages using route-guards.

See you later 👋👋 bye.. bye..


Feel free to comment down in the comment box… If I missed anything or anything is incorrect or anything does not works for you :)
Stay connected for more articles.