Telerik blogs

Angular has five types of route guards for controlling access to specific routes. Learn how to implement them in five steps, with the CanActivate route guard as an example.

A route guard is a feature that controls access to specific routes in the Angular application. It can protect routes from unauthorized access, require certain conditions be met before navigating to a route or perform other checks and actions during the navigation process.

Angular provides five types of route guards:

  1. CanActivate
  2. CanActivateChild
  3. CanDeactivate
  4. CanLoad
  5. Resolve

Most of the time, you use either CanActivate or CanActivateChild. The CanActivate guard determines whether a route can be activated, and the CanActivateChild determines whether a child route can be activated.

In this post, we will learn to create and apply a CanActivate route guard to the routes.

Step 1: Create the Route

You can create a route with lazy-loaded components as below:

export const routes: Routes = [
  {
    path: 'login',
    loadComponent: () =>
      import('./login/login.component').then((m) => m.LoginComponent),
  },
  {
    path: '',
    children: [
      {
        path: 'home',
        loadComponent: () =>
          import('./home/home.component').then((m) => m.HomeComponent),
      },
      {
        path: 'product',
        loadComponent: () =>
          import('./product/product.component').then((m) => m.ProductComponent),
      },
      {
        path: 'invoice',
        loadComponent: () =>
          import('./invoice/invoice.component').then((m) => m.InvoiceComponent),
      },
      {
        path: '',
        redirectTo: '/home',
        pathMatch: 'full',
      },
      {
        path: '**',
        component: PageNotFoundComponent,
      },
    ],
  },
];

As shown in the routes above, several components, such as ProductComponent, InvoiceComponent and HomeComponent, are lazily loaded. Additionally, a LoginComponent will handle navigation for unauthorized users, redirecting them to the login route.

One crucial point about the Login route is that it is not included as a child of the main route.

Step 2: Configure the Route

In the newer versions of Angular, you must provide the route at the ApplicationConfig, as demonstrated below.

export const appConfig: ApplicationConfig = {
  providers: [
     provideZoneChangeDetection({ eventCoalescing: true }),
     provideRouter(routes), 
     provideHttpClient(),
     provideAnimationsAsync()]
};

Step 3: Create Auth Service

In the Auth Service, we will create two separate functions: one to handle the Login operation and another to read the token from local storage to determine whether the user is logged in.

If you’re familiar with the basics of Angular, you already know how to perform a POST operation to a REST endpoint. In this case, we set the Content-Type header and use HttpClient to make the POST request to the Login endpoint.

login(user: ILoginUser): Observable<any> {
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
    });
    return this.httpClient.post('http://localhost:3000/login', user, {
      headers,
    });
  }

The isLoggedIn function is created as shown below:

  isLoggedIn(): Observable<boolean> {
    const token = localStorage.getItem('token');
    if (token) {
      return of(true);
    }
    return of(false);
  }

The isLoggedIn function is designed to determine whether a user is currently logged in by checking for the presence of a token in the browser’s local storage and whether the retrieved token exists.

The user is logged in if the token is found (i.e., not null or undefined). If a token exists, it returns an observable that emits true; otherwise, it returns an observable that emits false.

Bringing it all together, the AuthService looks like the following code snippet:

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';

import { ILoginUser } from './loginuser.interface';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private httpClient = inject(HttpClient);
  public redirectUrl: string | null = null;
  constructor() {}

  login(user: ILoginUser): Observable<any> {
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
    });
    return this.httpClient.post('http://localhost:3000/login', user, {
      headers,
    });
  }

  isLoggedIn(): Observable<boolean> {
    const token = localStorage.getItem('token');
    if (token) {
      return of(true);
    }
    return of(false);
  }
}

Take note of the redirectUrl declaration. You will use it to navigate back to the route where the login process was originally initiated.

Step 4: Create Login Component

In the Login component, set up a reactive form that includes fields for the username and password.

this.loginForm = this.fb.group({
      username: ['', [Validators.required]],
      password: ['', [Validators.required]],
    });

Then, the template binds the reactive form to the HTML controls, as shown below.

<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
  <div class="form-group">
    <label for="username">Username</label>
    <input type="text" class="form-control" formControlName="username" id="username">
  </div>
  <div class="form-group">
    <label for="password">Password</label>
    <input type="password" class="form-control" formControlName="password" id="password">
  </div>
  <button type="submit" class="btn btn-primary">Login</button>
  </form>

Create the onSubmit method to handle the click event for the Login button.

onSubmit(): void {
    if (this.loginForm.valid) {
      this.authService.login(this.loginForm.value).subscribe((data) => {
        if (data) {
          localStorage.setItem('token', data.token);
          const redirectUrl = this.authService.redirectUrl
            ? this.authService.redirectUrl
            : '/';
          this.router.navigate([redirectUrl]);
          this.authService.redirectUrl = null;
        }
      });
    }
  }

The onSubmit method performs the following tasks:

  • It checks whether the form is valid or not.
  • It calls the login function of authService.
  • On a successful response, it saves the token in the browser’s local storage.
  • It determines the URL to redirect the user to after a successful login.
  • It checks if a redirect URL is set in the service. If it is, the user is redirected to that URL; otherwise, the user is redirected to the root URL.

In summary, it performs the login operation, saves the token and redirects to the URL set in the service.

Step 5: Applying the Route Guard

Finally, apply the route guard to the route. In this case, use the canActivate route guard on the main route, as demonstrated below.

export const routes: Routes = [
  {
    path: 'login',
    loadComponent: () =>
      import('./login/login.component').then((m) => m.LoginComponent),
  },
  {
    path: '',
    canActivate: [authGuard],
    children: [
      // all paths 
    ],
  },
];

Summary

These steps are required to add a route guard in an Angular application. To summarize, a route guard in Angular helps control who can access specific pages in your app. It helps protect pages from users who shouldn’t see them, like those who aren’t logged in, and it requires certain conditions be met before opening a page.

I hope you find this post valuable and confident in implementing route guards in your Angular application.


Dhananjay Kumar
About the Author

Dhananjay Kumar

Dhananjay Kumar is an independent trainer and consultant from India. He is a published author, a well-known speaker, a Google Developer Expert, and a 10-time winner of the Microsoft MVP Award. He is the founder of geek97, which trains developers on various technologies so that they can be job-ready, and organizes India's largest Angular Conference, ng-India. He is the author of the best-selling book on Angular, Angular Essential. Find him on Twitter or GitHub.

Related Posts

Comments

Comments are disabled in preview mode.
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy