Angular 10/9 Router CanActivate Guards and UrlTree Parsed Routes

Angular 10/9 Router CanActivate Guards and UrlTree Parsed Routes

In the previous tutorial, we have added routing in our developer portfolio web application created with Angular 10. Let's now secure the UI with router canactivate guards.

Using Angular 10 Guards and UrlTree Interface for Protecting UIs

We'll be learning how to use Router Guards and UrlTree data structures to protect the UI if the user is not logged in and redirect them to the login interface if they don't have access to a specific route.

The admin interface can be only accessed by the website owner so we need to use Guards to protect the components of the admin module and only allow access to them if the user is logged in.

Creating a CanActivate Route Guard with Angular CLI 10

First, you need to create a route guard. Run the following command in your terminal to generate a guard service:

$ ng g guard admin/admin

Note: We prefix the guard name with the admin/ path to generate it inside the admin folder for the matter of code organization.

Two src/app/admin/admin.guard.spec.ts and src/app/admin/admin.guard.ts files will be generated. Open the src/app/admin/admin.guard.ts file, you should see the following code:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AdminGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

From the code, you see that a guard is simply a service that implements the CanActivate interface and overrides the canActivate() method. In this case, it always returns true which means access will be always granted to the user when this guard is applied to a route.

Note: There are other types of Guards such as:

  • CanActivateChild: used to allow or disallow access to child routes.
  • CanDeactivate: used to allow or deny exit from route.
  • Resolve`: used for doing operations (resolve data) just before route activation etc.

Let's change the method to only allow access if the user is logged in. First, you need to import AuthService and inject it via the AdminGuard service and next you need to call the isLoggedIn property in the canActivate() method to check if the user is logged in and return true or false;

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

import { AuthService } from './auth/auth.service';

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

  constructor(private authService: AuthService){}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      return this.authService.isLoggedIn;
  }
}

The canActivate() method will return true if the user is logged in or false otherwise.

The canActivate() method is passed many arguments which makes it easy to detrmine if the guard needs to allow or disallow access to certain route(s):

  1. next: ActivatedRouteSnapshotwhich is the next route that will be activated if the guard is allowing access,
  2. state: RouterStateSnapshotwhich is the next router state if the guard is allowing access.

Applying the Angular Guard

Now, you need to apply the guard to the routes you need to protect using the canActivate property of the path object. Open the src/app/admin/admin-routing.module.ts file and update it accordingly:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { ProjectComponent } from './project/project.component';
import { ProjectListComponent } from './project-list/project-list.component';
import { ProjectCreateComponent } from './project-create/project-create.component';
import { ProjectUpdateComponent } from './project-update/project-update.component';
import { LoginComponent } from './login/login.component';
import { AdminGuard } from  './admin.guard';

const routes: Routes = [
    {
        path: 'admin',
        component: ProjectComponent,
        children: [
            {
                path: 'list',
                component: ProjectListComponent,
                canActivate: [AdminGuard]
            },            
            {
                path: 'create',
                component: ProjectCreateComponent,
                canActivate: [AdminGuard]
            },
            {
                path: 'update',
                component: ProjectUpdateComponent,
                canActivate: [AdminGuard]
            },
            { 
                path: 'login', 
                component: LoginComponent 
            }
        ]
    }
];


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

We protected the ProjectListComponent, ProjectCreateComponent and ProjectUpdateComponent components of the admin module from non logged in users.

Note: The canActivate property of the path object takes an array which means you can register multiple guards.

Before Angular 7.1, route guards can only return a boolean, Promise<boolean> or Observable<boolean> (asynchronous boolean objects) to tell the router if the route can be activated or not. But now, you can also return an UrlTree variable which provides the new router state (route) that should be activated.

According to the Angular docs an UrlTree is a data structure that represents a parsed URL.

Note: You can create an UrlTree by calling the parseUrl() or createUrlTree() method of the Router object.

Now, let's change our router guard to redirect the users to the /admin/login route if they try to access the protected admin components without being logged in first:

  • First, we import and inject the router,
  • Next, we update the canActivate() method to return an UrlTree corresponding to the /admin/login route.

This is the full code of the AdminGuard service:

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

@Injectable({
  providedIn: 'root'
})
export class AdminGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router)
  {}
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean | UrlTree {
    if(this.authService.isLoggedIn){
      return true;
    }
    else{
      return this.router.parseUrl("/admin/login");
    }

  }
}

We check if the user is logged in and we return true, otherwise we return the result from the parseUrl("/admin/login") method of the injected router instance which is an UrlTreeof the /admin/login route.

Now, go to your application, if you visit any protected route without logging in you will be redirected to the /admin/login route where you can login.

Check out all parts:

Conclusion

As a recap, we’ve seen how to use route guards some new features introduced in Angular v7.1+ enables you to redirect to another route by using a UrlTree parsed route.

In this tutorial, we've used Angular Guards and UrlTree structures that correspond to parsed routes to disallow access to certain routes if users are not logged in. In the next tutorial, we'll proceed by implementing the CRUD operations of the admin interface which allows the portfolio owner to add projects to their website. We'll be using Firestore as our persistence layer.



Angular 9 Components: Input and Output
Angular 13 selectors
Picture-in-Picture with JavaScript and Angular 10
Jasmine Unit Testing for Angular 12
Angular 9 Tutorial By Example: REST CRUD APIs & HTTP GET Requests with HttpClient
Angular 10/9 Elements Tutorial by Example: Building Web Components
Angular 10/9 Router Tutorial: Learn Routing & Navigation by Example
Angular 10/9 Router CanActivate Guards and UrlTree Parsed Routes
Angular 10/9 JWT Authentication Tutorial with Example
Style Angular 10/9 Components with CSS and ngStyle/ngClass Directives
Upload Images In TypeScript/Node & Angular 9/Ionic 5: Working with Imports, Decorators, Async/Await and FormData
Angular 9/Ionic 5 Chat App: Unsubscribe from RxJS Subjects, OnDestroy/OnInit and ChangeDetectorRef
Adding UI Guards, Auto-Scrolling, Auth State, Typing Indicators and File Attachments with FileReader to your Angular 9/Ionic 5 Chat App
Private Chat Rooms in Angular 9/Ionic 5: Working with TypeScript Strings, Arrays, Promises, and RxJS Behavior/Replay Subjects
Building a Chat App with TypeScript/Node.js, Ionic 5/Angular 9 & PubNub/Chatkit
Chat Read Cursors with Angular 9/Ionic 5 Chat App: Working with TypeScript Variables/Methods & Textarea Keydown/Focusin Events
Add JWT REST API Authentication to Your Node.js/TypeScript Backend with TypeORM and SQLite3 Database
Building Chat App Frontend UI with JWT Auth Using Ionic 5/Angular 9
Install Angular 10 CLI with NPM and Create a New Example App with Routing
Styling An Angular 10 Example App with Bootstrap 4 Navbar, Jumbotron, Tables, Forms and Cards
Integrate Bootstrap 4/jQuery with Angular 10 and Styling the UI With Navbar and Table CSS Classes
Angular 10/9 Tutorial and Example: Build your First Angular App
Angular 9/8 ngIf Tutorial & Example
Angular 10 New Features
Create New Angular 9 Workspace and Application: Using Build and Serve
Angular 10 Release Date: Angular 10 Will Focus on Ivy Artifacts and Libraries Support
HTML5 Download Attribute with TypeScript and Angular 9
Angular 9.1+ Local Direction Query API: getLocaleDirection Example
Angular 9.1 displayBlock CLI Component Generator Option by Example
Angular 9 Basics Tutorial by Example
Angular 9/8 ngFor Directive: Render Arrays with ngFor by Example
Responsive Image Breakpoints Example with CDK's BreakpointObserver in Angular 9/8
Angular 9/8 DOM Queries: ViewChild and ViewChildren Example
The Angular 9/8 Router: Route Parameters with Snapshot and ParamMap by Example
Angular 9/8 Nested Routing and Child Routes by Example
Angular 9 Examples: 2 Ways To Display A Component (Selector & Router)
Angular 9/8 Tutorial: Http POST to Node/Express.js Example
Angular 9/8 Feature and Root Modules by Example
Angular 9/8 with PHP: Consuming a RESTful CRUD API with HttpClient and Forms
Angular 9/8 with PHP and MySQL Database: REST CRUD Example & Tutorial
Unit Testing Angular 9/8 Apps Tutorial with Jasmine & Karma by Example
Angular 9 Web Components: Custom Elements & Shadow DOM
Angular 9 Renderer2 with Directives Tutorial by Example
Build Progressive Web Apps (PWA) with Angular 9/8 Tutorial and Example
Angular 9 Internationalization/Localization with ngx-translate Tutorial and Example
Create Angular 9 Calendar with ngx-bootstrap datepicker Example and Tutorial
Multiple File Upload with Angular 9 FormData and PHP by Example
Angular 9/8 Reactive Forms with Validation Tutorial by Example
Angular 9/8 Template Forms Tutorial: Example Authentication Form (ngModel/ngForm/ngSubmit)
Angular 9/8 JAMStack By Example
Angular HttpClient v9/8 — Building a Service for Sending API Calls and Fetching Data
Build an Angular 9/8 CRUD Example & Tutorial
Styling An Angular 9/8/7 Example App with Bootstrap 4 Navbar, Jumbotron, Tables, Forms and Cards
Angular 8/7 Tutorial By Example: (REST API, HttpClient GET, Components, Services & ngFor)

✋If you have any questions about this article, ask them in our GitHub Discussions 👈 community. You can also Gitter

✋ Want to master Angular 14? Read our angular tutorial and join our #DailyAngularChallenge where we learn to build components, directives, services, pipes and complete web, mobile, and desktop applications with latest Angular version.

✋ Make sure to join our Angular 14 Dev Community 👈 to discuss anything related to Angular development.

❤️ Like our page and subscribe to our feed for updates!