Introducción

En aplicaciones Angular, las guardias de ruta (route guards) son una herramienta esencial para controlar el acceso a diferentes rutas basándose en ciertas condiciones. Las guardias de ruta permiten proteger rutas específicas, asegurando que solo los usuarios autorizados o que cumplen ciertos criterios puedan acceder a ellas.

Tipos de Guardias de Ruta

Angular proporciona varios tipos de guardias de ruta que se pueden implementar:

  1. CanActivate: Determina si una ruta puede ser activada.
  2. CanActivateChild: Determina si las rutas hijas de una ruta pueden ser activadas.
  3. CanDeactivate: Determina si se puede salir de una ruta.
  4. CanLoad: Determina si un módulo puede ser cargado.
  5. Resolve: Prepara datos antes de que se active una ruta.

Implementación de Guardias de Ruta

Paso 1: Crear una Guardia de Ruta

Para crear una guardia de ruta, utilizamos el Angular CLI. Por ejemplo, para crear una guardia AuthGuard que implemente CanActivate, ejecutamos el siguiente comando:

ng generate guard auth

Este comando generará un archivo auth.guard.ts con una estructura básica.

Paso 2: Implementar la Lógica de la Guardia

Editamos el archivo auth.guard.ts para implementar la lógica de la guardia. A continuación, se muestra un ejemplo de una guardia que verifica si el usuario está autenticado:

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

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

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

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if (this.authService.isLoggedIn()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

Paso 3: Registrar la Guardia en las Rutas

Para utilizar la guardia AuthGuard, la registramos en las rutas correspondientes en el archivo de configuración de rutas (app-routing.module.ts):

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

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

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

Ejemplo Completo

A continuación, se muestra un ejemplo completo que incluye un servicio de autenticación (auth.service.ts), la guardia de ruta (auth.guard.ts) y la configuración de rutas (app-routing.module.ts).

auth.service.ts

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

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

  login() {
    this.loggedIn = true;
  }

  logout() {
    this.loggedIn = false;
  }

  isLoggedIn(): boolean {
    return this.loggedIn;
  }
}

auth.guard.ts

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

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

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

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if (this.authService.isLoggedIn()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

app-routing.module.ts

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

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

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

Ejercicio Práctico

Ejercicio

  1. Objetivo: Crear una guardia de ruta que permita el acceso a una ruta solo si el usuario tiene un rol específico.
  2. Pasos:
    • Crear un servicio RoleService que gestione los roles de los usuarios.
    • Crear una guardia RoleGuard que implemente CanActivate y verifique el rol del usuario.
    • Registrar la guardia en una ruta específica.

Solución

role.service.ts

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

@Injectable({
  providedIn: 'root'
})
export class RoleService {
  private userRole: string = 'guest';

  setRole(role: string) {
    this.userRole = role;
  }

  getRole(): string {
    return this.userRole;
  }
}

role.guard.ts

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

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

  constructor(private roleService: RoleService, private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    const expectedRole = next.data.expectedRole;
    if (this.roleService.getRole() === expectedRole) {
      return true;
    } else {
      this.router.navigate(['/unauthorized']);
      return false;
    }
  }
}

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { UnauthorizedComponent } from './unauthorized/unauthorized.component';
import { RoleGuard } from './role.guard';

const routes: Routes = [
  { path: 'home', component: HomeComponent, canActivate: [RoleGuard], data: { expectedRole: 'admin' } },
  { path: 'login', component: LoginComponent },
  { path: 'unauthorized', component: UnauthorizedComponent },
  { path: '', redirectTo: '/home', pathMatch: 'full' }
];

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

Conclusión

Las guardias de ruta en Angular son una herramienta poderosa para controlar el acceso a diferentes partes de una aplicación. Permiten implementar lógica de seguridad y autorización de manera eficiente, asegurando que solo los usuarios adecuados puedan acceder a ciertas rutas. En este módulo, hemos aprendido a crear y utilizar diferentes tipos de guardias de ruta, así como a implementar una guardia personalizada basada en roles de usuario.

Curso de Angular

Módulo 1: Introducción a Angular

Módulo 2: Componentes de Angular

Módulo 3: Enlace de Datos y Directivas

Módulo 4: Servicios e Inyección de Dependencias

Módulo 5: Enrutamiento y Navegación

Módulo 6: Formularios en Angular

Módulo 7: Cliente HTTP y Observables

Módulo 8: Gestión de Estado

Módulo 9: Pruebas en Angular

Módulo 10: Conceptos Avanzados de Angular

Módulo 11: Despliegue y Mejores Prácticas

© Copyright 2024. Todos los derechos reservados