Saltar al contenido principal

Autenticación y Autorización

Estrategia de Autenticación

IRIS utiliza un sistema de autenticación híbrido que combina JWT (JSON Web Tokens) para APIs y sesiones tradicionales para la interfaz web.

JSON Web Tokens (JWT)

Configuración

const JWT_CONFIG = {
secret: process.env.JWT_SECRET || 'iris-default-secret',
expiresIn: '24h',
issuer: 'iris-api',
algorithm: 'HS256'
};

Estructura del Token

{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "user-id",
"iss": "iris-api",
"iat": 1640995200,
"exp": 1641081600,
"roles": ["user", "admin"],
"permissions": ["read", "write", "process"]
}
}

Flujo de Autenticación

Middleware de Autenticación

Implementación

const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!token) {
return res.status(401).json({
error: 'Access token required'
});
}

jwt.verify(token, JWT_CONFIG.secret, (err, user) => {
if (err) {
return res.status(403).json({
error: 'Invalid or expired token'
});
}

req.user = user;
next();
});
};

Rutas Protegidas

// Rutas que requieren autenticación
app.use('/api/process', authenticateToken);
app.use('/api/admin', authenticateToken, requireRole('admin'));
app.use('/api/upload', authenticateToken, requirePermission('write'));

Roles y Permisos

Definición de Roles

const ROLES = {
admin: {
permissions: ['read', 'write', 'delete', 'admin', 'process'],
description: 'Acceso completo al sistema'
},
operator: {
permissions: ['read', 'write', 'process'],
description: 'Operador del sistema OCR'
},
viewer: {
permissions: ['read'],
description: 'Solo lectura'
}
};

Middleware de Autorización

const requireRole = (role) => {
return (req, res, next) => {
const userRoles = req.user.roles || [];

if (!userRoles.includes(role)) {
return res.status(403).json({
error: 'Insufficient privileges'
});
}

next();
};
};

const requirePermission = (permission) => {
return (req, res, next) => {
const userPermissions = req.user.permissions || [];

if (!userPermissions.includes(permission)) {
return res.status(403).json({
error: `Permission '${permission}' required`
});
}

next();
};
};

Configuración de CORS

const corsOptions = {
origin: function (origin, callback) {
const allowedOrigins = [
'http://localhost:3000',
'https://iris.example.com'
];

if (!origin || allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
optionsSuccessStatus: 200
};

app.use(cors(corsOptions));

Rate Limiting

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100, // límite de 100 requests por ventana
message: {
error: 'Too many requests, please try again later'
},
standardHeaders: true,
legacyHeaders: false
});

app.use('/api/', limiter);

Seguridad Adicional

Headers de Seguridad

const helmet = require('helmet');

app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));

Validación de Input

const { body, validationResult } = require('express-validator');

const validateLogin = [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
error: 'Validation failed',
details: errors.array()
});
}
next();
}
];

Variables de Entorno

# Configuración JWT
JWT_SECRET=your-super-secret-key-here
JWT_EXPIRES_IN=24h

# Configuración CORS
ALLOWED_ORIGINS=http://localhost:3000,https://iris.example.com

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100