Sistema NEXUS v3.4 migrado con: Estructura principal: - core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles) - core/catalog: Catalogo de funcionalidades reutilizables - shared/knowledge-base: Base de conocimiento compartida - devtools/scripts: Herramientas de desarrollo - control-plane/registries: Control de servicios y CI/CD - orchestration/: Configuracion de orquestacion de agentes Proyectos incluidos (11): - gamilit (submodule -> GitHub) - trading-platform (OrbiquanTIA) - erp-suite con 5 verticales: - erp-core, construccion, vidrio-templado - mecanicas-diesel, retail, clinicas - betting-analytics - inmobiliaria-analytics - platform_marketing_content - pos-micro, erp-basico Configuracion: - .gitignore completo para Node.js/Python/Docker - gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git) - Sistema de puertos estandarizado (3005-3199) Generated with NEXUS v3.4 Migration System EPIC-010: Configuracion Git y Repositorios
355 lines
6.5 KiB
Markdown
355 lines
6.5 KiB
Markdown
# Limitación de Tasa (Rate Limiting)
|
|
|
|
**Versión:** 1.0.0
|
|
**Origen:** projects/gamilit
|
|
**Estado:** Producción
|
|
**Última actualización:** 2025-12-08
|
|
|
|
---
|
|
|
|
## Descripción
|
|
|
|
Sistema de limitación de tasa para proteger APIs contra abuso:
|
|
- Rate limiting por IP/usuario
|
|
- Configuración por endpoint
|
|
- Headers HTTP estándar
|
|
- Respuestas 429 con Retry-After
|
|
|
|
---
|
|
|
|
## Características
|
|
|
|
| Característica | Descripción |
|
|
|----------------|-------------|
|
|
| Por IP | Limita requests por dirección IP |
|
|
| Por Usuario | Limita requests por usuario autenticado |
|
|
| Por Endpoint | Configuración individual por ruta |
|
|
| Global | Límite base para toda la aplicación |
|
|
| Headers Estándar | X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After |
|
|
|
|
---
|
|
|
|
## Stack Tecnológico
|
|
|
|
```yaml
|
|
backend:
|
|
framework: NestJS
|
|
library: "@nestjs/throttler"
|
|
storage: "Memory (default) | Redis (producción)"
|
|
```
|
|
|
|
---
|
|
|
|
## Dependencias NPM
|
|
|
|
```json
|
|
{
|
|
"@nestjs/throttler": "^5.x"
|
|
}
|
|
```
|
|
|
|
Para producción con Redis:
|
|
```json
|
|
{
|
|
"@nestjs/throttler-storage-redis": "^0.x",
|
|
"redis": "^4.x"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Configuración Básica
|
|
|
|
### En módulo principal
|
|
|
|
```typescript
|
|
import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
|
|
import { APP_GUARD } from '@nestjs/core';
|
|
|
|
@Module({
|
|
imports: [
|
|
ThrottlerModule.forRoot([{
|
|
ttl: 60000, // 60 segundos
|
|
limit: 100, // 100 requests por TTL
|
|
}]),
|
|
],
|
|
providers: [
|
|
{
|
|
provide: APP_GUARD,
|
|
useClass: ThrottlerGuard,
|
|
},
|
|
],
|
|
})
|
|
export class AppModule {}
|
|
```
|
|
|
|
### Configuración por ambiente
|
|
|
|
```typescript
|
|
ThrottlerModule.forRootAsync({
|
|
imports: [ConfigModule],
|
|
inject: [ConfigService],
|
|
useFactory: (config: ConfigService) => ([{
|
|
ttl: config.get('THROTTLE_TTL', 60000),
|
|
limit: config.get('THROTTLE_LIMIT', 100),
|
|
}]),
|
|
})
|
|
```
|
|
|
|
---
|
|
|
|
## Uso por Endpoint
|
|
|
|
### Sobrescribir límites
|
|
|
|
```typescript
|
|
import { Throttle, SkipThrottle } from '@nestjs/throttler';
|
|
|
|
@Controller('auth')
|
|
export class AuthController {
|
|
|
|
// Más estricto: 5 intentos por minuto
|
|
@Throttle({ default: { limit: 5, ttl: 60000 } })
|
|
@Post('login')
|
|
login() {}
|
|
|
|
// Omitir rate limiting
|
|
@SkipThrottle()
|
|
@Get('public')
|
|
publicEndpoint() {}
|
|
}
|
|
```
|
|
|
|
### En controlador completo
|
|
|
|
```typescript
|
|
@Controller('api')
|
|
@Throttle({ default: { limit: 50, ttl: 60000 } })
|
|
export class ApiController {
|
|
// Todos los endpoints heredan el límite
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Múltiples Límites
|
|
|
|
```typescript
|
|
ThrottlerModule.forRoot([
|
|
{
|
|
name: 'short',
|
|
ttl: 1000, // 1 segundo
|
|
limit: 3, // 3 requests por segundo
|
|
},
|
|
{
|
|
name: 'medium',
|
|
ttl: 10000, // 10 segundos
|
|
limit: 20, // 20 requests por 10 segundos
|
|
},
|
|
{
|
|
name: 'long',
|
|
ttl: 60000, // 1 minuto
|
|
limit: 100, // 100 requests por minuto
|
|
},
|
|
])
|
|
```
|
|
|
|
Usar en endpoint:
|
|
|
|
```typescript
|
|
@Throttle({
|
|
short: { limit: 1, ttl: 1000 },
|
|
long: { limit: 10, ttl: 60000 },
|
|
})
|
|
@Post('expensive-operation')
|
|
expensiveOperation() {}
|
|
```
|
|
|
|
---
|
|
|
|
## Rate Limiting por Usuario
|
|
|
|
### Custom ThrottlerGuard
|
|
|
|
```typescript
|
|
import { Injectable, ExecutionContext } from '@nestjs/common';
|
|
import { ThrottlerGuard } from '@nestjs/throttler';
|
|
|
|
@Injectable()
|
|
export class CustomThrottlerGuard extends ThrottlerGuard {
|
|
protected async getTracker(req: Record<string, any>): Promise<string> {
|
|
// Si hay usuario autenticado, usar su ID
|
|
if (req.user?.id) {
|
|
return req.user.id;
|
|
}
|
|
// Fallback a IP
|
|
return req.ip;
|
|
}
|
|
}
|
|
```
|
|
|
|
Registrar:
|
|
|
|
```typescript
|
|
providers: [
|
|
{
|
|
provide: APP_GUARD,
|
|
useClass: CustomThrottlerGuard,
|
|
},
|
|
],
|
|
```
|
|
|
|
---
|
|
|
|
## Almacenamiento Redis (Producción)
|
|
|
|
```typescript
|
|
import { ThrottlerStorageRedisService } from '@nestjs/throttler-storage-redis';
|
|
import Redis from 'ioredis';
|
|
|
|
ThrottlerModule.forRootAsync({
|
|
imports: [ConfigModule],
|
|
inject: [ConfigService],
|
|
useFactory: (config: ConfigService) => ({
|
|
throttlers: [{
|
|
ttl: config.get('THROTTLE_TTL', 60000),
|
|
limit: config.get('THROTTLE_LIMIT', 100),
|
|
}],
|
|
storage: new ThrottlerStorageRedisService(new Redis({
|
|
host: config.get('REDIS_HOST', 'localhost'),
|
|
port: config.get('REDIS_PORT', 6379),
|
|
})),
|
|
}),
|
|
})
|
|
```
|
|
|
|
---
|
|
|
|
## Headers de Respuesta
|
|
|
|
El módulo agrega automáticamente:
|
|
|
|
```
|
|
X-RateLimit-Limit: 100 # Límite máximo
|
|
X-RateLimit-Remaining: 95 # Requests restantes
|
|
X-RateLimit-Reset: 1234567890 # Timestamp de reset
|
|
```
|
|
|
|
En respuesta 429:
|
|
|
|
```
|
|
Retry-After: 60 # Segundos hasta poder reintentar
|
|
```
|
|
|
|
---
|
|
|
|
## Excepciones Personalizadas
|
|
|
|
```typescript
|
|
import { ThrottlerException } from '@nestjs/throttler';
|
|
|
|
// En el guard personalizado
|
|
protected throwThrottlingException(): void {
|
|
throw new ThrottlerException(
|
|
'Demasiadas solicitudes. Por favor, espere un momento.',
|
|
);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Variables de Entorno
|
|
|
|
```env
|
|
# Configuración básica
|
|
THROTTLE_TTL=60000 # Ventana de tiempo en ms
|
|
THROTTLE_LIMIT=100 # Requests por ventana
|
|
|
|
# Redis (producción)
|
|
REDIS_HOST=localhost
|
|
REDIS_PORT=6379
|
|
```
|
|
|
|
---
|
|
|
|
## Casos de Uso Comunes
|
|
|
|
### 1. Login (anti brute-force)
|
|
|
|
```typescript
|
|
@Throttle({ default: { limit: 5, ttl: 300000 } }) // 5 por 5 minutos
|
|
@Post('login')
|
|
login() {}
|
|
```
|
|
|
|
### 2. Registro (anti spam)
|
|
|
|
```typescript
|
|
@Throttle({ default: { limit: 3, ttl: 3600000 } }) // 3 por hora
|
|
@Post('register')
|
|
register() {}
|
|
```
|
|
|
|
### 3. API pública
|
|
|
|
```typescript
|
|
@Throttle({ default: { limit: 1000, ttl: 3600000 } }) // 1000 por hora
|
|
@Get('public-data')
|
|
getData() {}
|
|
```
|
|
|
|
### 4. Endpoints costosos
|
|
|
|
```typescript
|
|
@Throttle({ default: { limit: 10, ttl: 60000 } }) // 10 por minuto
|
|
@Post('generate-report')
|
|
generateReport() {}
|
|
```
|
|
|
|
---
|
|
|
|
## Métricas y Logging
|
|
|
|
```typescript
|
|
@Injectable()
|
|
export class ThrottlerLoggerGuard extends ThrottlerGuard {
|
|
protected async handleRequest(
|
|
context: ExecutionContext,
|
|
limit: number,
|
|
ttl: number,
|
|
): Promise<boolean> {
|
|
const req = context.switchToHttp().getRequest();
|
|
const tracker = await this.getTracker(req);
|
|
|
|
const result = await super.handleRequest(context, limit, ttl);
|
|
|
|
if (!result) {
|
|
this.logger.warn(`Rate limit exceeded for: ${tracker}`);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Adaptaciones Necesarias
|
|
|
|
1. **Límites**: Ajustar según tráfico esperado
|
|
2. **Storage**: Memory para desarrollo, Redis para producción
|
|
3. **Tracker**: IP vs Usuario según necesidad
|
|
4. **Mensajes**: Personalizar respuestas 429
|
|
|
|
---
|
|
|
|
## Referencias
|
|
|
|
- [NestJS Throttler](https://docs.nestjs.com/security/rate-limiting)
|
|
- [RFC 6585](https://tools.ietf.org/html/rfc6585#section-4) (429 Too Many Requests)
|
|
|
|
---
|
|
|
|
**Mantenido por:** Sistema NEXUS
|
|
**Proyecto origen:** Gamilit Platform
|