Route Guards para autenticación y autorización

Avanzado
Angular
Angular
Actualizado: 18/04/2026

Route Guards funcionales en Angular 21

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

En Angular 21, los guards se implementan como funciones que utilizan inject() para acceder a servicios. Este enfoque funcional es el estándar recomendado por su simplicidad, mejor tree-shaking y compatibilidad natural con el patrón standalone.

Tipos de guards funcionales

  1. CanActivateFn: Se ejecuta antes de que se active una ruta. Se usa principalmente para proteger rutas que requieren autenticación.
  2. CanDeactivateFn: Se utiliza para manejar la navegación fuera de una ruta. Ideal para advertir sobre cambios no guardados.
  3. CanActivateChildFn: Similar a CanActivateFn, pero se aplica a todas las rutas hijas.
  4. CanMatchFn: Determina si una configuración de ruta coincide con la URL actual. Útil para lazy loading condicional.
  5. ResolveFn: Permite pre-cargar datos antes de que se active una ruta.

Crear un AuthGuard funcional (CanActivateFn)

Generar un guard

Utilizamos Angular CLI:

ng generate guard auth

Implementar el guard funcional

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

export const authGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const router = inject(Router);

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

Implementar el servicio de autenticación

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

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

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

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

  logout() {
    this.authenticated = false;
  }
}

Configurar rutas con el guard

Las rutas se configuran en app.routes.ts con provideRouter() en app.config.ts:

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

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

Ejemplos prácticos

Confirmación de salida con CanDeactivateFn

Este guard previene que un usuario abandone una página accidentalmente sin guardar cambios:

// 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;
  };

Implementación en el componente:

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

@Component({
  selector: 'app-edit',
  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] 
  },
];

Cargar datos con ResolveFn

El resolver funcional permite precargar datos antes de activar una ruta:

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

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

En la configuración de rutas:

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

Proteger rutas hijas con CanActivateChildFn

// 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);

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

En la configuración de rutas, el guard se aplica a la ruta padre y protege todas sus rutas hijas:

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

Controlar lazy loading con CanMatchFn

CanMatchFn reemplaza al antiguo CanLoad y determina si una ruta coincide con la URL actual, permitiendo lazy loading condicional:

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

export const matchGuard: CanMatchFn = (route, segments) => {
  const authService = inject(AuthService);

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

En la configuración de rutas:

export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes').then(m => m.default),
    canMatch: [matchGuard],
  },
];

Enfoque legacy: Guards basados en clases

En versiones anteriores de Angular, los guards se implementaban como clases que implementaban interfaces como CanActivate, CanDeactivate, etc. Este enfoque legacy sigue funcionando en aplicaciones existentes pero no es el recomendado para nuevos proyectos en Angular 21.

// Enfoque legacy (no recomendado en Angular 21)
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if (this.authService.isLoggedIn()) {
      return true;
    }
    this.router.navigate(['login']);
    return false;
  }
}

El enfoque funcional con CanActivateFn, CanDeactivateFn, CanMatchFn y ResolveFn es más conciso, tiene mejor tree-shaking y se integra naturalmente con el patrón standalone de Angular 21.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Angular

Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Entender los diferentes tipos de Route Guards funcionales en Angular. Implementar CanActivateFn para proteger rutas que requieren autenticación. Usar CanDeactivateFn para manejar navegación fuera de una ruta. Proteger rutas hijas con CanActivateChildFn. Pre-cargar datos antes de la activación de una ruta con ResolveFn. Integrar y configurar Route Guards funcionales en aplicaciones standalone.