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
302 lines
7.2 KiB
Markdown
302 lines
7.2 KiB
Markdown
# Gestión de Sesiones
|
|
|
|
**Versión:** 1.0.0
|
|
**Origen:** projects/gamilit
|
|
**Estado:** Producción
|
|
**Última actualización:** 2025-12-08
|
|
|
|
---
|
|
|
|
## Descripción
|
|
|
|
Sistema de gestión de sesiones de usuario con:
|
|
- Múltiples sesiones concurrentes (máx 5)
|
|
- Tracking de dispositivo, IP, ubicación
|
|
- Renovación automática con refresh tokens
|
|
- Revocación individual y masiva
|
|
- Limpieza automática de sesiones expiradas
|
|
|
|
---
|
|
|
|
## Características
|
|
|
|
| Característica | Descripción |
|
|
|----------------|-------------|
|
|
| Multi-sesión | Hasta 5 sesiones concurrentes por usuario |
|
|
| Auto-limpieza | Sesiones más antiguas eliminadas automáticamente |
|
|
| Device Tracking | IP, User-Agent, dispositivo, navegador, OS |
|
|
| Geo-location | País y ciudad (si disponible) |
|
|
| Refresh Tokens | Hasheados con SHA256 |
|
|
| Revocación | Individual o masiva |
|
|
| Multi-tenant | Soporte para múltiples tenants |
|
|
|
|
---
|
|
|
|
## Stack Tecnológico
|
|
|
|
```yaml
|
|
backend:
|
|
framework: NestJS
|
|
orm: TypeORM
|
|
crypto: Node.js crypto (SHA256)
|
|
|
|
database:
|
|
engine: PostgreSQL
|
|
schemas:
|
|
- auth_management (sesiones)
|
|
```
|
|
|
|
---
|
|
|
|
## Dependencias NPM
|
|
|
|
```json
|
|
{
|
|
"typeorm": "^0.3.x",
|
|
"@nestjs/typeorm": "^10.x"
|
|
}
|
|
```
|
|
|
|
Nota: crypto es nativo de Node.js, no requiere instalación.
|
|
|
|
---
|
|
|
|
## Tabla Requerida
|
|
|
|
```sql
|
|
CREATE TABLE auth_management.user_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
tenant_id UUID,
|
|
session_token TEXT NOT NULL UNIQUE,
|
|
refresh_token TEXT, -- Hasheado con SHA256
|
|
user_agent TEXT,
|
|
ip_address INET,
|
|
device_type VARCHAR(50), -- desktop, mobile, tablet, unknown
|
|
browser VARCHAR(100),
|
|
os VARCHAR(100),
|
|
country VARCHAR(100),
|
|
city VARCHAR(100),
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
last_activity_at TIMESTAMPTZ DEFAULT NOW(),
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
revoked_at TIMESTAMPTZ,
|
|
metadata JSONB DEFAULT '{}'
|
|
);
|
|
|
|
-- Índices
|
|
CREATE INDEX idx_user_sessions_user_id ON auth_management.user_sessions(user_id);
|
|
CREATE INDEX idx_user_sessions_tenant_id ON auth_management.user_sessions(tenant_id);
|
|
CREATE INDEX idx_user_sessions_session_token ON auth_management.user_sessions(session_token);
|
|
CREATE INDEX idx_user_sessions_expires_at ON auth_management.user_sessions(expires_at);
|
|
```
|
|
|
|
---
|
|
|
|
## Estructura del Módulo
|
|
|
|
```
|
|
session-management/
|
|
├── services/
|
|
│ └── session-management.service.ts
|
|
├── entities/
|
|
│ └── user-session.entity.ts
|
|
├── dto/
|
|
│ ├── create-user-session.dto.ts
|
|
│ ├── update-user-session.dto.ts
|
|
│ └── user-session-response.dto.ts
|
|
└── __tests__/
|
|
└── session-management.service.spec.ts
|
|
```
|
|
|
|
---
|
|
|
|
## API del Servicio
|
|
|
|
```typescript
|
|
class SessionManagementService {
|
|
// Crear nueva sesión
|
|
async createSession(dto: CreateUserSessionDto): Promise<UserSession>;
|
|
|
|
// Validar sesión y actualizar actividad
|
|
async validateSession(sessionId: string): Promise<UserSession | null>;
|
|
|
|
// Renovar sesión
|
|
async refreshSession(sessionId: string, newExpiresAt: Date): Promise<UserSession>;
|
|
|
|
// Revocar sesión específica
|
|
async revokeSession(sessionId: string, userId: string): Promise<{ message: string }>;
|
|
|
|
// Revocar todas excepto la actual
|
|
async revokeAllSessions(userId: string, currentSessionId: string): Promise<{ message: string; count: number }>;
|
|
|
|
// Limpiar sesiones expiradas (cron)
|
|
async cleanExpiredSessions(): Promise<number>;
|
|
|
|
// Obtener sesiones activas del usuario
|
|
async getSessions(userId: string): Promise<UserSession[]>;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Uso Rápido
|
|
|
|
### 1. Crear sesión al login
|
|
|
|
```typescript
|
|
import { SessionManagementService } from '@/modules/auth/services';
|
|
|
|
// En AuthService.login()
|
|
const session = await this.sessionManagementService.createSession({
|
|
user_id: user.id,
|
|
tenant_id: profile.tenant_id,
|
|
session_token: crypto.randomBytes(32).toString('hex'),
|
|
refresh_token: refreshToken, // Será hasheado internamente
|
|
ip_address: req.ip,
|
|
user_agent: req.headers['user-agent'],
|
|
device_type: this.detectDeviceType(userAgent),
|
|
browser: this.detectBrowser(userAgent),
|
|
os: this.detectOS(userAgent),
|
|
expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 días
|
|
});
|
|
```
|
|
|
|
### 2. Obtener sesiones activas
|
|
|
|
```typescript
|
|
// En UsersController
|
|
@Get('sessions')
|
|
@UseGuards(JwtAuthGuard)
|
|
async getSessions(@Request() req) {
|
|
return this.sessionManagementService.getSessions(req.user.id);
|
|
}
|
|
```
|
|
|
|
### 3. Revocar sesión
|
|
|
|
```typescript
|
|
// En UsersController
|
|
@Delete('sessions/:id')
|
|
@UseGuards(JwtAuthGuard)
|
|
async revokeSession(@Param('id') sessionId: string, @Request() req) {
|
|
return this.sessionManagementService.revokeSession(sessionId, req.user.id);
|
|
}
|
|
```
|
|
|
|
### 4. Cerrar todas las sesiones
|
|
|
|
```typescript
|
|
// En UsersController
|
|
@Post('sessions/revoke-all')
|
|
@UseGuards(JwtAuthGuard)
|
|
async revokeAllSessions(@Request() req, @Body() body: { currentSessionId: string }) {
|
|
return this.sessionManagementService.revokeAllSessions(
|
|
req.user.id,
|
|
body.currentSessionId
|
|
);
|
|
}
|
|
```
|
|
|
|
### 5. Cron job para limpieza
|
|
|
|
```typescript
|
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
|
|
@Cron(CronExpression.EVERY_HOUR)
|
|
async cleanExpiredSessions() {
|
|
const count = await this.sessionManagementService.cleanExpiredSessions();
|
|
this.logger.log(`Limpiadas ${count} sesiones expiradas`);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Comportamientos Clave
|
|
|
|
### Límite de Sesiones
|
|
|
|
```typescript
|
|
MAX_SESSIONS_PER_USER = 5;
|
|
|
|
// Al crear la 6ta sesión:
|
|
// 1. Se eliminan sesiones expiradas
|
|
// 2. Si aún hay 5+, se elimina la más antigua
|
|
// 3. Se crea la nueva sesión
|
|
```
|
|
|
|
### Hasheo de Refresh Tokens
|
|
|
|
```typescript
|
|
// El refresh token se hashea antes de guardar en BD
|
|
const hashedToken = crypto.createHash('sha256')
|
|
.update(refreshToken)
|
|
.digest('hex');
|
|
```
|
|
|
|
### Validación de Propiedad
|
|
|
|
```typescript
|
|
// Solo el dueño puede revocar sus sesiones
|
|
await this.sessionRepository.findOne({
|
|
where: { id: sessionId, user_id: userId }, // Validación de ownership
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Flujo de Sesiones
|
|
|
|
```
|
|
LOGIN
|
|
│
|
|
├─► Crear sesión con tokens
|
|
│ ├─► Limpiar expiradas
|
|
│ ├─► Si >5, eliminar antigua
|
|
│ └─► Guardar nueva sesión
|
|
│
|
|
REFRESH
|
|
│
|
|
├─► Validar refresh token
|
|
├─► Buscar sesión por hash
|
|
└─► Actualizar expiración
|
|
│
|
|
LOGOUT
|
|
│
|
|
└─► Marcar sesión como inactiva
|
|
└─► Establecer revoked_at
|
|
```
|
|
|
|
---
|
|
|
|
## Seguridad
|
|
|
|
- Refresh tokens nunca se almacenan en texto plano
|
|
- Validación de ownership en revocación
|
|
- Soft delete con `is_active = false` y `revoked_at`
|
|
- Limpieza periódica de datos obsoletos
|
|
- No se serializa `refresh_token` en respuestas
|
|
|
|
---
|
|
|
|
## Adaptaciones Necesarias
|
|
|
|
1. **Límite de sesiones**: Ajustar `MAX_SESSIONS_PER_USER` según necesidades
|
|
2. **Tiempo de expiración**: Configurar según política de seguridad
|
|
3. **Geo-location**: Implementar si se requiere país/ciudad
|
|
4. **Multi-tenant**: Omitir `tenant_id` si no aplica
|
|
5. **Cron schedule**: Ajustar frecuencia de limpieza
|
|
|
|
---
|
|
|
|
## Referencias
|
|
|
|
- Código completo: `projects/gamilit/apps/backend/src/modules/auth/services/session-management.service.ts`
|
|
- Entity: `projects/gamilit/apps/backend/src/modules/auth/entities/user-session.entity.ts`
|
|
|
|
---
|
|
|
|
**Mantenido por:** Sistema NEXUS
|
|
**Proyecto origen:** Gamilit Platform
|