Angular

Angular

Tutorial Angular: Route Guards basados en interfaces

Aprende a usar Angular Route Guards para implementar autenticación y autorización en tu aplicación. Protege rutas, maneja navegación y pre-carga datos de manera eficiente.

¿Qué es un route guard?

Un route guard en Angular es una interfaz que permite controlar la navegación a una ruta específica y decidir si dicha navegación debe ser permitida o no

Los route guards se utilizan comúnmente para implementar lógicas de autenticación y autorización, aunque también pueden servir para diversas comprobaciones o condiciones antes de que se cargue una ruta.

Ejemplos de route guards basados en interfaces

  1. CanActivate: Este guard se ejecuta antes de que se active una ruta. Se usa principalmente para proteger rutas que requieren autenticación.
  2. CanDeactivate: Se utiliza para manejar la navegación fuera de una ruta. Es útil, por ejemplo, para advertir a los usuarios sobre la posible pérdida de cambios no guardados.
  3. CanActivateChild: Similar al CanActivate, pero se aplica a rutas hijas. Permite proteger rutas secundarias dentro de una aplicación.
  4. CanLoad: Se usa para evitar que se cargue un módulo que se está cargando de manera diferida hasta que se cumpla alguna condición. Ideal para optimizar la carga de recursos en aplicaciones grandes.
  5. Resolve: Permite pre-cargar datos antes de que se active una ruta. Este guard es útil para asegurar que los datos necesarios estén disponibles antes de que la vista sea renderizada.

Crear un AuthGuard (CanActivate)

Para crear un guard utilizando la interfaz CanActivate, seguimos estos pasos:

Generar un nuevo guard

Utilizamos Angular CLI para generar un guard. Esto se hace de la siguiente manera:

1.- Abre una terminal en el directorio raíz de tu proyecto Angular.

2.- Ejecuta el siguiente comando:

ng generate guard auth

O la versión abreviada:

ng g guard auth

3.- Angular CLI te preguntará qué interfaces quieres implementar. Selecciona CanActivate usando las teclas de flecha y presiona la barra espaciadora para marcarla. Luego presiona Enter.

4.- El CLI generará el archivo auth.guard.ts en la carpeta src/app.

Implementar el método canActivate

En el archivo generado (auth.guard.ts), implementamos la lógica de verificación de autenticación.

Ejemplo básico de uso

Para implementar un AuthGuard en Angular, primero debemos crear un guard utilizando una de las interfaces de guard disponibles. En este ejemplo, usaremos CanActivate, pero Angular ofrece otras interfaces como CanDeactivate, CanActivateChild, y CanLoad para diferentes escenarios.

A continuación, se detalla el proceso paso a paso para crear un AuthGuard básico, implementar un servicio de autenticación y proteger las rutas en la aplicación. Este enfoque se puede adaptar para usar otras interfaces de guard según las necesidades específicas del proyecto.

Aplicaciones con módulo raíz tradicional

Implementación del AuthGuard

Primero, creamos el AuthGuard. Debemos asegurarnos de que este guard verifica si el usuario está autenticado antes de permitir el acceso a una ruta específica.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service'; // Servicio de autenticación
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    const isAuthenticated = this.authService.isLoggedIn(); // Método para verificar si está autenticado
    if (!isAuthenticated) {
      this.router.navigate(['login']); // Redirige al login si no está autenticado
      return false;
    }
    return true;
  }
}

Implementación del servicio de autenticación

El siguiente paso es implementar el servicio de autenticación (AuthService). Este servicio debe tener un método que verifique si el usuario está autenticado o no.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private authenticated: boolean = false;

  // Simulación de login
  login(username: string, password: string): boolean {
    if (username === 'user' && password === 'password') {
      this.authenticated = true;
      return true;
    }
    return false;
  }

  // Método que comprueba el estado de autenticación
  isLoggedIn(): boolean {
    return this.authenticated;
  }

  // Simulación de logout
  logout() {
    this.authenticated = false;
  }
}

Integración del AuthGuard en las rutas de la aplicación

Una vez que tenemos implementado tanto el AuthGuard como el AuthService, podemos proceder a la integración del guard en las rutas de la aplicación para protegerlas. 

Modificamos el módulo de rutas (AppRoutingModule) para incluir el guard en las rutas que queremos proteger.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth.guard';
import { HomeComponent } from './home/home.component'; // Componente protegido
import { LoginComponent } from './login/login.component'; // Componente de login

const routes: Routes = [
  { path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
  { path: '**', redirectTo: 'home' },
];

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

Aplicaciones con Standalone Components

Implementación del AuthGuard

En aplicaciones standalone, el AuthGuard se implementa como una función en lugar de una clase. Esto permite una sintaxis más concisa y el uso de la función inject() para la inyección de dependencias.

// auth.guard.ts
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth.service';

export const authGuard = () => {
  const authService = inject(AuthService);
  const router = inject(Router);

  if (authService.isLoggedIn()) {
    return true;
  }
  return router.parseUrl('/login');
};

Implementación del servicio de autenticación

El servicio de autenticación permanece igual que en el ejemplo anterior, ya que los servicios funcionan de manera similar tanto en aplicaciones tradicionales como en standalone.

Configuración de rutas con el AuthGuard

En aplicaciones standalone, las rutas se configuran directamente en el archivo principal (generalmente main.ts). Aquí, utilizamos bootstrapApplication y provideRouter para configurar la aplicación y sus rutas.

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { Routes, provideRouter } from '@angular/router';
import { AppComponent } from './app/app.component';
import { authGuard } from './app/auth.guard';

const routes: Routes = [
  {
    path: 'home',
    loadComponent: () => import('./app/home/home.component').then(m => m.HomeComponent),
    canActivate: [authGuard]
  },
  {
    path: 'login',
    loadComponent: () => import('./app/login/login.component').then(m => m.LoginComponent)
  },
  { path: '', redirectTo: '/home', pathMatch: 'full' },
];

bootstrapApplication(AppComponent, {
  providers: [provideRouter(routes)]
}).catch(err => console.error(err));

Ejemplos prácticos

Crear un AuthGuard (CanActivate)

Para crear un guard utilizando la interfaz CanActivate, seguimos estos pasos:

  1. Generar un nuevo guard: Utilizamos Angular CLI para generar un guard.
  2. Implementar el método canActivate: En el archivo generado (auth.guard.ts), implementamos la lógica de verificación de autenticación.

Confirmación de salida con CanDeactivate

Este guard se utiliza para prevenir que un usuario abandone una página accidentalmente sin guardar cambios. Es particularmente útil en formularios o editores.

El CanDeactivateGuard implementa la interfaz CanDeactivate. Comprueba si el componente tiene un método canDeactivate() y lo ejecuta. Este método puede devolver un booleano, una promesa o un observable.

// can-deactivate.guard.ts
import { CanDeactivateFn } from '@angular/router';

export type CanDeactivateComponent = {
  canDeactivate: () => boolean | Promise<boolean> | import('rxjs').Observable<boolean>
};

export const canDeactivateGuard: CanDeactivateFn<CanDeactivateComponent> = 
  (component) => {
    return component.canDeactivate ? component.canDeactivate() : true;
  };

En el componente, implementamos la lógica real de confirmación. En este caso, se muestra un simple cuadro de diálogo de confirmación, pero en una aplicación real, podría comprobar si hay cambios no guardados y mostrar un mensaje más específico.

// edit.component.ts
import { Component } from '@angular/core';
import { CanDeactivateComponent } from './can-deactivate.guard';

@Component({
  selector: 'app-edit',
  standalone: true,
  template: '<h1>Edit Component</h1>',
})
export class EditComponent implements CanDeactivateComponent {
  canDeactivate(): boolean {
    return confirm('Do you want to discard changes?');
  }
}

Para usar este guard en las rutas:

// app.routes.ts
import { Routes } from '@angular/router';
import { EditComponent } from './edit.component';
import { canDeactivateGuard } from './can-deactivate.guard';

export const routes: Routes = [
  { 
    path: 'edit', 
    component: EditComponent, 
    canDeactivate: [canDeactivateGuard] 
  },
  // ... otras rutas
];

Cargar datos con Resolve

El resolver es una herramienta poderosa para precargar datos antes de que se active una ruta. Esto asegura que la información necesaria esté disponible antes de que se muestre el componente, mejorando la experiencia del usuario.

En este ejemplo, el DataResolver implementa la interfaz Resolve. Utiliza un DataService para obtener los datos. El método resolve() se ejecuta antes de que la ruta se active, y la navegación no se completa hasta que los datos se resuelven.

// data.resolver.ts
import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { Observable } from 'rxjs';
import { DataService } from './data.service';

export const dataResolver: ResolveFn<any> = (
  route,
  state
): Observable<any> => {
  const dataService = inject(DataService);
  return dataService.getData();
};

Suponiendo que tenemos un DataService:

// data.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  getData(): Observable<any> {
    return of({ message: 'Datos precargados' });
  }
}

En la configuración de rutas, asociamos el resolver a una ruta específica. Los datos resueltos estarán disponibles en el componente a través de ActivatedRoute.

// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { dataResolver } from './data.resolver';

export const routes: Routes = [
  { 
    path: 'home', 
    component: HomeComponent, 
    resolve: { data: dataResolver } 
  },
  // ... otras rutas
];

Proteger rutas hijas con CanActivateChild

CanActivateChild es útil cuando tenemos un conjunto de rutas hijas que queremos proteger con la misma lógica de autorización. En lugar de aplicar un guard a cada ruta hija individualmente, podemos usar CanActivateChild en la ruta padre.

El ChildAuthGuard implementa CanActivateChild. Su lógica es similar a un CanActivate normal, pero se aplica a todas las rutas hijas. En este caso, verifica si el usuario está autenticado antes de permitir el acceso a cualquier ruta hija.

// child-auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateChildFn, Router } from '@angular/router';
import { AuthService } from './auth.service';

export const childAuthGuard: CanActivateChildFn = (childRoute, state) => {
  const authService = inject(AuthService);
  const router = inject(Router);

  const isAuthenticated = authService.isLoggedIn();
  if (!isAuthenticated) {
    router.navigate(['login']);
    return false;
  }
  return true;
};

Suponiendo que tenemos un AuthService:

// auth.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  isLoggedIn(): boolean {
    // Implementación real de verificación de autenticación
    return true; // Ejemplo simplificado
  }
}

En la configuración de rutas, aplicamos el guard a la ruta padre (dashboard), y todas sus rutas hijas heredarán esta protección.

const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivateChild: [ChildAuthGuard],
    children: [
      { path: 'profile', component: ProfileComponent },
      { path: 'settings', component: SettingsComponent },
    ],
  },
];

Controlar la carga diferida con CanLoad

CanLoad es un guard especialmente diseñado para trabajar con la carga diferida (lazy loading) de módulos. Previene que un módulo se cargue si no se cumplen ciertas condiciones, lo que puede ser útil para optimizar el rendimiento y la seguridad.

El LoadGuard implementa CanLoad. Verifica si el usuario está autenticado antes de permitir la carga del módulo. Si el usuario no está autenticado, redirige al login y previene la carga del módulo.

// load.guard.ts
import { inject } from '@angular/core';
import { CanLoadFn, Router } from '@angular/router';
import { AuthService } from './auth.service';

export const loadGuard: CanLoadFn = (route, segments) => {
  const authService = inject(AuthService);
  const router = inject(Router);

  const isAuthenticated = authService.isLoggedIn();
  if (!isAuthenticated) {
    router.navigate(['login']);
    return false;
  }
  return true;
};

En la configuración de rutas, aplicamos CanLoad a una ruta que usa loadChildren para cargar un módulo de forma diferida. Esto asegura que el módulo solo se cargará si el guard lo permite.

// app.routes.ts
import { Routes } from '@angular/router';
import { loadGuard } from './load.guard';

export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES),
    canLoad: [loadGuard],
  },
  // ... otras rutas
];

Para el módulo admin, ahora usaremos un archivo de rutas standalone:

// admin/admin.routes.ts
import { Routes } from '@angular/router';
import { AdminComponent } from './admin.component';

export const ADMIN_ROUTES: Routes = [
  { path: '', component: AdminComponent },
  // ... otras rutas admin
];

El componente Admin puede ser standalone:

// admin/admin.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-admin',
  standalone: true,
  template: '<h1>Admin Dashboard</h1>'
})
export class AdminComponent {}
Certifícate en Angular con CertiDevs PLUS

Ejercicios de esta lección Route Guards basados en interfaces

Evalúa tus conocimientos de esta lección Route Guards basados en interfaces con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Signals en Angular

Angular
Puzzle

Guards funcionales

Angular
Test

Decodificar JWT en Angular

Angular
Test

Servicio con HttpClient

Angular
Código

Ciclo de vida de componentes en Angular

Angular
Test

Gestión de productos de Fake Store API

Angular
Proyecto

Data binding en Angular

Angular
Test

Routes sin módulos en Angular

Angular
Código

Router en Angular

Angular
Test

Instalación de Angular

Angular
Puzzle

Route Guards basados en interfaces

Angular
Código

La directiva @if en Angular

Angular
Puzzle

Formularios reactivos en Angular

Angular
Código

Servicios en Angular

Angular
Puzzle

Interceptor funcional

Angular
Test

Servicio con Array

Angular
Código

La directiva @for en Angular

Angular
Puzzle

Interceptores HTTP

Angular
Código

Componentes standalone true

Angular
Puzzle

Formularios con ngModel en Angular

Angular
Puzzle

Routes en Angular

Angular
Test

Comunicación entre componentes Angular

Angular
Test

Parámetros en rutas con ActivatedRoute

Angular
Test

CRUD de Restaurantes y Platos

Angular
Proyecto

Tablas en Angular Material

Angular
Puzzle

Formulario de registro de usuarios

Angular
Proyecto

Instalación y uso de NgBoostrap

Angular
Puzzle

Desarrollo de componentes Angular

Angular
Test

JWT en Angular

Angular
Código

Formularios reactivos en Angular

Angular
Puzzle

Formularios en Angular Material

Angular
Puzzle

Layout con Angular Material

Angular
Puzzle

Effects en Angular

Angular
Test

Data binding

Angular
Código

HttpClient en servicios de Angular

Angular
Puzzle

Desarrollo de módulos Angular

Angular
Puzzle

Comandos Angular CLI

Angular
Puzzle

Subir archivo en formularios

Angular
Test

La directiva routerLink en Angular

Angular
Test

Todas las lecciones de Angular

Accede a todas las lecciones de Angular y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Instalación Angular

Angular

Introducción Y Entorno

Comandos Angular Cli

Angular

Introducción Y Entorno

Desarrollo De Componentes Angular

Angular

Componentes

Data Binding En Angular

Angular

Componentes

Ciclo De Vida De Componentes En Angular

Angular

Componentes

Comunicación Entre Componentes Angular

Angular

Componentes

La Directiva @If En Angular

Angular

Componentes

La Directiva @For En Angular

Angular

Componentes

Componentes Standalone

Angular

Componentes

Desarrollo De Módulos Angular

Angular

Módulos

Routes En Angular

Angular

Enrutado Y Navegación

Router En Angular

Angular

Enrutado Y Navegación

La Directiva Routerlink En Angular

Angular

Enrutado Y Navegación

Parámetros En Rutas Con Activatedroute

Angular

Enrutado Y Navegación

Routes Sin Módulos En Angular

Angular

Enrutado Y Navegación

Servicios En Angular

Angular

Servicios E Inyección De Dependencias

Httpclient En Servicios De Angular

Angular

Servicios E Inyección De Dependencias

Formularios Con Ngmodel En Angular

Angular

Formularios

Formularios Reactivos En Angular

Angular

Formularios

Subir Archivo En Formularios

Angular

Formularios

Layout Con Angular Material

Angular

Integración Con Angular Material

Tablas En Angular Material

Angular

Integración Con Angular Material

Formularios En Angular Material

Angular

Integración Con Angular Material

Instalación Y Uso De Ngboostrap

Angular

Integración Con Bootstrap Css

Signals En Angular

Angular

Signals Y Reactividad

Effects En Angular

Angular

Signals Y Reactividad

Route Guards Basados En Interfaces

Angular

Autenticación Y Autorización

Guards Funcionales

Angular

Autenticación Y Autorización

Interceptores Http Basados En Interfaz

Angular

Autenticación Y Autorización

Interceptores Http Funcionales

Angular

Autenticación Y Autorización

Seguridad Jwt En Angular

Angular

Autenticación Y Autorización

Decodificar Tokens Jwt En Angular

Angular

Autenticación Y Autorización

Certificados de superación de Angular

Supera todos los ejercicios de programación del curso de Angular y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  • Entender los diferentes tipos de Route Guards en Angular.

  • Implementar CanActivate para proteger rutas que requieren autenticación.

  • Usar CanDeactivate para manejar navegación fuera de una ruta.

  • Proteger rutas hijas con CanActivateChild.

  • Controlar la carga diferida de módulos con CanLoad.

  • Pre-cargar datos antes de la activación de una ruta con Resolve.

  • Integrar y configurar Route Guards en aplicaciones tanto tradicionales como standalone.