Introducción
flowchart TD
NAV["Navegación a /admin"] --> ROUTER["Router"]
ROUTER --> GUARD["CanActivateFn (función guard)"]
GUARD --> AUTH["AuthenticationService.getIsAdmin()"]
AUTH -->|true| ALLOW["Permitir acceso al componente"]
AUTH -->|false| BLOCK["Bloquear y redirigir a /login"]
GUARD --> INJECT["inject(): acceso a servicios"]
GUARD --> CHILD["CanActivateChild: rutas hijas"]
GUARD --> LOAD["CanMatch: carga diferida"]
Los guards en angular se utilizan para proteger rutas de accesos no autorizados.
Por ejemplo se podrían utilizar para proteger una pantalla de formulario de creación de libros (book-form.component.html) de ser accedida por un usuario que no tenga el rol ADMIN y solo tenga el rol USER.
Crear un guard
Crear un Guard para comprobar si el usuario tiene rol ADMIN y permitir el paso a las rutas.
Ejecutar el comando:
ng generate guard authentication/role-admin
El resultado es un nuevo archivo llamado role-admin.guard.ts con el siguiente contenido:
import { CanActivateFn} from '@angular/router';
export const roleAdminGuard: CanActivateFn = (route, state) => {
return true;
};
Comprobar el rol del usuario en el guard
Para comprobar el rol del usuario se utilizaría un AuthenticationService y que devolvería true o false si el usuario tiene rol ADMIN:
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthenticationService } from './authentication.service';
export const roleAdminGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthenticationService);
const router = inject(Router);
// Si el usuario es administrador entonces puede entrar en la pantalla
if (authService.getIsAdmin()){
return true;
} else {
return router.navigate(['/login']); // si no es admin entonces redirige a login
}
};
Proteger rutas con el guard
Una vez creado el guard, podemos proteger rutas en el archivo app.routes.ts:
{
path: 'authors',
component: AuthorListComponent
},
{
path: 'authors/:id/detail',
component: AuthorDetailComponent
},
{
path: 'authors/create',
component: AuthorFormComponent,
canActivate: [roleAdminGuard]
},
{
path: 'authors/:id/update',
component: AuthorFormComponent,
canActivate: [roleAdminGuard]
},
Con este código canActivate: [roleAdminGuard] en las rutas deseadas logramos que solo los usuarios con rol ADMIN puedan acceder a esas rutas, y si no tienen rol ADMIN entonces serán redirigidos hacia la pantalla de login.
Crear guard para comprobar login
Crear un nuevo guard para proteger rutas y que solo sean accesibles por usuarios autenticados, sin tener en cuenta su rol, solo si está autenticado sí o no:
ng generate guard authentication/user-logged-in
Resultado:

Pulsamos enter y se genera el guard:

Código generado:
import { CanActivateFn } from '@angular/router';
export const userLoggedInGuard: CanActivateFn = (route, state) => {
return true;
};
En este guard comprobamos si el usuario ha iniciado sesión con la ayuda del AuthenticationService:
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthenticationService } from './authentication.service';
export const userLoggedInGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthenticationService);
const router = inject(Router);
if (authService.existsToken()) {
return true;
} else {
return router.navigate(['/login']);
}
};
Una vez completado el código del guard lo utilizamos sobre las rutas que se desea proteger en app.routes.ts:
Por ejemplo:
{
path: 'books/:id/detail',
component: BookDetailComponent,
canActivate: [userLoggedInGuard]
}
De este modo podemos tener múltiples guards para proteger las rutas:

Resultado:
Si un usuario intenta entrar a los componentes que tienen el guard sin hacer primero el login será redirigido automáticamente hacia la pantalla de login, no pudiendo entrar al componente sin haberse identificado primero.
Caso B2B: control de acceso en backoffices y portales
En entidades bancarias con backoffices que distinguen entre operadores, supervisores y auditores, los guards funcionales materializan el control RBAC en el cliente Angular. Vuestro equipo configura típicamente un guard por rol (adminGuard, auditorGuard, operadorGuard) y los compone en las rutas. Aunque la seguridad real reside en el backend (que valida cada llamada con el JWT y el rol), el guard en el cliente evita mostrar pantallas que el usuario no puede usar, mejorando la UX y reduciendo llamadas API innecesarias. La organización gana en cumplimiento de SoD (Segregation of Duties) exigido por DORA.
En administraciones públicas con sedes electrónicas, los guards distinguen entre usuarios autenticados con Cl@ve (ciudadano), Cl@ve PIN, certificado digital y representante legal. Cada nivel de garantía abre rutas distintas: declaración simple para Cl@ve, presentación con firma electrónica para certificado. Vuestro equipo modela esto con CanActivateFn que consulta el nivel de garantía del token recibido del IdP.
En telco con portales de cliente B2B, los guards verifican que el usuario tenga al menos un contrato activo o un rol contractual concreto (administrador, gestor de líneas, financiero) antes de mostrar las secciones correspondientes. La organización gana porque la lógica vive en un único punto, fácil de auditar.
En retail con paneles para proveedores, CanMatch (introducido en Angular 14) permite cargar diferentes módulos según el tipo de proveedor sin descargar bundles de roles que el usuario no usa. Esto reduce el TTI (Time to Interactive) en conexiones lentas.
Versiones (2025)
Los guards funcionales sustituyen a los antiguos guards basados en clases (CanActivate, CanDeactivate, CanLoad). Disponibles desde Angular 14 (junio 2022), son la forma recomendada en Angular 16+, y los basados en clases están deprecados en Angular 18 (con eliminación futura). En Angular 19 (noviembre 2024), los tipos disponibles son:
CanActivateFn: protege la activación de una ruta.CanActivateChildFn: protege rutas hijas.CanDeactivateFn<T>: confirma la salida de una ruta (típicamente con formularios sin guardar).CanMatchFn: decide si una ruta hace match (sustituye aCanLoad, más versátil).ResolveFn<T>: pre-carga datos antes de activar la ruta.
inject() reemplaza el constructor de servicios y solo funciona dentro de contextos de inyección Angular (incluidos los guards funcionales).
Anti-patrones y pitfalls
Confiar la seguridad solo al guard del cliente. El guard se ejecuta en el navegador y un atacante con DevTools puede saltarlo trivialmente. El backend debe validar siempre cada petición con su token y rol. El guard es UX, no seguridad.
Lógica asíncrona compleja con setTimeout o sin desuscripción. Los guards deben devolver boolean | UrlTree | Observable<boolean | UrlTree> | Promise<...>. Si vuestra comprobación es async (consultar API), retornad un Observable o Promise; Angular se suscribe y desuscribe automáticamente.
Redirección con router.navigate(['/login']) sin return. router.navigate retorna una promesa, pero el guard espera un valor síncrono o asíncrono. Si no retornáis, Angular permite el acceso.
Guards encadenados que dependen del orden. Si una ruta tiene [guardA, guardB], ambos se ejecutan en paralelo. Si guardA debe completarse antes que guardB, conviene combinarlos en un único guard.
Inyectar servicios fuera del contexto de inyección. inject(AuthenticationService) solo funciona dentro de la función guard. Si extraéis lógica a una función externa, pasad el servicio como parámetro.
Olvidar CanDeactivate en formularios con cambios sin guardar. Es la forma idiomática de avisar al usuario "tienes cambios sin guardar, ¿salir?".
Comparativa con alternativas
Frente a guards basados en clases, los funcionales son más concisos, menos verboso de testear y se integran mejor con inject() standalone. Para nuevo código, son la opción canónica.
Frente a interceptores HTTP que manejan 401/403 globalmente, los guards previenen la navegación; los interceptores reaccionan a errores. Ambos son complementarios: el guard mejora la UX, el interceptor maneja el caso límite donde el guard no se aplicó (por ejemplo, una API llamada desde un componente público).
Frente a lazy loading sin guard, CanMatch permite condicionalmente cargar módulos. Esto reduce el bundle inicial: si el usuario no es admin, no descarga el módulo admin.
Frente a sistemas como Auth0 SDK o Keycloak Angular adapter, los guards funcionales se integran con cualquiera. Auth0 y Keycloak proveen guards listos para usar; podéis envolverlos o componerlos.
Documentación oficial
La referencia es angular.dev/guide/routing/route-guards-functions (la antigua angular.io/guide/router#preventing-unauthorized-access redirige). Para inject(), angular.dev/api/core/inject. El blog oficial de Angular publicó en 2022 la migración a guards funcionales con ejemplos.
Los guards funcionales son la forma moderna y recomendada de proteger rutas en Angular 19. Para vuestro equipo en proyectos B2B, son la herramienta canónica para implementar control de acceso a nivel de ruta, siempre como complemento (no sustituto) de la validación en el backend.
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
Crear un Guard con Angular CLI. Comprobar el rol del usuario desde el Guard. Utilizar el Guard en las rutas en app.routes.ts. Proteger rutas de usuarios no autenticados. Proteger rutas de usuarios no autorizados.