Introducción a los Guards
Los Guards en NestJS son una característica fundamental del sistema de seguridad que permite controlar el acceso a rutas y recursos específicos de tu aplicación. Funcionan como filtros de autorización que se ejecutan antes de que una petición llegue al controlador, determinando si debe procesarse o rechazarse.
Un Guard implementa la interfaz CanActivate
y debe devolver un valor booleano que indica si la petición actual está autorizada para continuar. Esta decisión puede basarse en diversos factores como la autenticación del usuario, sus permisos, roles o cualquier lógica de negocio específica.
Funcionamiento básico de los Guards
Los Guards se ejecutan después de los middlewares pero antes de los interceptors y pipes. Esta posición en el ciclo de vida de la petición los convierte en el lugar ideal para implementar lógica de autorización, ya que pueden detener el procesamiento antes de que se ejecute cualquier lógica de negocio.
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
// Lógica de validación
return this.validateRequest(request);
}
private validateRequest(request: any): boolean {
// Ejemplo: verificar si existe un token de autorización
return request.headers.authorization !== undefined;
}
}
Tipos de Guards en NestJS
NestJS permite implementar diferentes tipos de Guards según las necesidades de tu aplicación:
Guards de autenticación: Verifican si el usuario está autenticado correctamente. Suelen validar tokens JWT, cookies de sesión o credenciales básicas.
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
return false;
}
try {
const payload = this.jwtService.verify(token);
request.user = payload;
return true;
} catch {
return false;
}
}
private extractTokenFromHeader(request: any): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
Guards de autorización: Verifican si el usuario autenticado tiene los permisos necesarios para acceder a un recurso específico. Evalúan roles, permisos o políticas de acceso.
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
Aplicación de Guards
Los Guards pueden aplicarse a diferentes niveles de tu aplicación, proporcionando flexibilidad en el control de acceso:
A nivel global: Afecta a todas las rutas de la aplicación.
import { APP_GUARD } from '@nestjs/core';
@Module({
providers: [
{
provide: APP_GUARD,
useClass: AuthGuard,
},
],
})
export class AppModule {}
A nivel de controlador: Protege todas las rutas de un controlador específico.
@Controller('users')
@UseGuards(AuthGuard)
export class UsersController {
@Get()
findAll() {
return 'Esta ruta está protegida por el AuthGuard';
}
}
A nivel de método: Protege únicamente una ruta específica.
@Controller('users')
export class UsersController {
@Get('profile')
@UseGuards(AuthGuard, RolesGuard)
getProfile() {
return 'Ruta protegida por múltiples guards';
}
}
ExecutionContext y acceso a datos
El ExecutionContext proporciona acceso completo a los detalles de la petición actual. Este contexto permite a los Guards examinar la petición HTTP, extraer headers, parámetros y cualquier información necesaria para tomar decisiones de autorización.
@Injectable()
export class OwnershipGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const user = request.user;
const resourceId = request.params.id;
// Verificar si el usuario es propietario del recurso
return this.checkOwnership(user.id, resourceId);
}
private checkOwnership(userId: string, resourceId: string): boolean {
// Lógica para verificar propiedad del recurso
return true; // Simplificado para el ejemplo
}
}
Los Guards representan una herramienta esencial para implementar seguridad robusta en aplicaciones NestJS. Su integración natural con el sistema de inyección de dependencias permite crear soluciones de autorización complejas y reutilizables que se adaptan perfectamente a los requisitos de seguridad de aplicaciones empresariales.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Nest
Documentación oficial de Nest
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, Nest 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 Nest
Explora más contenido relacionado con Nest y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender qué son los Guards y su función en el ciclo de vida de una petición en NestJS.
- Aprender a implementar Guards personalizados que controlen la autenticación y autorización.
- Conocer los diferentes tipos de Guards y cuándo aplicarlos (autenticación, roles, propiedad).
- Saber cómo aplicar Guards a nivel global, de controlador y de método.
- Entender el uso de ExecutionContext para acceder a la información de la petición y tomar decisiones de seguridad.