José Matos
•25 Mar 2023
If you’re developing a single-page application using Angular, you’re going to need routing. Routing in Angular is a powerful feature that enables creating rich and complex user interfaces. With Angular routing, pages can be displayed and updated dynamically without having to reload the entire web page.
But what if you want to secure some of your app’s routes? You don’t want unauthorized users to have access to your application’s sensitive pages, right? This is where guards come into play.
Guards determine whether a user is authorized to access a route or not. They are essentially a set of rules that are added to a route, allowing you to control access to that route based on various criteria.
In this article, we’ll explore two kinds of guards in Angular - CanActivate and CanDeactivate - and how they can be used to secure your application’s routes.
The CanActivate guard is used to allow or prevent access to a particular route based on a condition. When a CanActivate guard is used on a route, Angular will run the guard’s check method before accessing the route, and only proceed if the check method returns true.
To create a CanActivate guard in Angular, you need to generate a guard using the Angular CLI by running the following command:
ng generate guard your-guard-name
This will generate a guard file named your-guard-name.guard.ts in your project’s src/app directory. Open this file and replace the generated file content with the following code:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class YourGuardNameGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree {
// Your condition goes here
const isLoggedIn = true;
if (isLoggedIn) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}
In the code above, we are creating a guard called YourGuardNameGuard, which implements the CanActivate interface. Inside the canActivate method, we are checking a condition to see if the user is authenticated. If the user is authenticated, canActivate returns true and allows the user to access the route. If the user is not authenticated, canActivate returns false and redirects the user to the login page.
Once you’ve created your guard, you can add it to any route in your application’s routing module. Let’s say that you have a route called /profile that should only be accessible by authenticated users. To add the guard to this route, modify your routing module to look something like this:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ProfileComponent } from './profile/profile.component';
import { YourGuardNameGuard } from './your-guard-name.guard';
const routes: Routes = [
{ path: 'profile', component: ProfileComponent, canActivate: [YourGuardNameGuard] },
// Your other routes go here
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
When a user tries to access the /profile route, Angular will run the canActivate method of your YourGuardNameGuard guard to check if they are authenticated.
While CanActivate guards secure routes before they are accessed, CanDeactivate guards secure routes as the user attempts to leave them. This is useful when you want to prevent the user from accidentally losing data or take some action before navigating away from a page.
To create a CanDeactivate guard in Angular, you need to generate a guard using the Angular CLI by running the following command:
ng generate guard your-deactivate-guard-name --implement CanDeactivate
This will generate a guard file named your-deactivate-guard-name.guard.ts in your project’s src/app directory. Open this file and replace the generated file content with the following code:
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';
export interface DeactivateComponent {
canDeactivate: () => Observable | Promise | boolean;
}
@Injectable({
providedIn: 'root'
})
export class YourDeactivateGuardNameGuard implements CanDeactivate {
canDeactivate(component: DeactivateComponent): Observable | Promise | boolean {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
In the code above, we are creating a guard called YourDeactivateGuardNameGuard, which implements the CanDeactivate interface. We declare an interface named DeactivateComponent with one method - canDeactivate - which returns a boolean or an Observable that resolves to a boolean.
Inside the CanDeactivate guard, we call the canDeactivate method of the component being navigated away from. If the component doesn’t implement the canDeactivate method, we assume that it can be deactivated and return true.
To use a CanDeactivate guard, first make sure that the component that you want to secure implements the DeactivateComponent interface. Let’s say that you have a route called /edit-profile, and you want to prompt the user to confirm unsaved changes before they leave the page. To add the guard to this route, modify your routing module to look something like this:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { EditProfileComponent } from './edit-profile/edit-profile.component';
import { YourDeactivateGuardNameGuard } from './your-deactivate-guard-name.guard';
const routes: Routes = [
{
path: 'edit-profile',
component: EditProfileComponent,
canDeactivate: [YourDeactivateGuardNameGuard]
},
// Your other routes go here
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
In the code above, we’re adding the YourDeactivateGuardNameGuard guard to the /edit-profile route by setting the canDeactivate property to an array of guards. Angular will now run YourDeactivateGuardNameGuard’s canDeactivate method whenever the user attempts to leave the /edit-profile route.
Routing in Angular is a powerful feature that allows you to create complex user interfaces. However, it’s important to secure some of your app’s routes to protect sensitive data. CanActivate and CanDeactivate guards are a simple yet effective way of securing your app’s routes.
In this article, we’ve shown you how to create CanActivate and CanDeactivate guards and use them to secure your application’s routes. By implementing guards, you can ensure your user’s data remains secure, guarded, and only authorized users can access sensitive parts of your application.