Autorización RBAC
Reglas
- Verifica los permisos en CADA ruta con middleware — nunca hagas la autorización opcional
- Denegar por defecto: si no se concede un permiso explícito, se deniega el acceso
- Aplicación del lado del servidor: ocultar elementos de la interfaz de usuario NO es seguridad, verifica en el servidor
- Define una jerarquía de roles: admin > editor > viewer — los roles superiores heredan permisos inferiores
- Verificaciones a nivel de recurso: verifica
can(user, "edit", resource) — no solo acceso basado en rol
- Audita todas las comprobaciones de permisos — registra quién accedió a qué y cuándo, especialmente para acciones de administración
- Separa la autenticación (¿quién eres?) de la autorización (¿qué puedes hacer?)
type Action = "read" | "create" | "update" | "delete";
type Resource = { ownerId: string; [key: string]: any };
function can(user: { id: string; role: string }, action: Action, resource?: Resource): boolean {
const permissions: Record<string, Action[]> = {
admin: ["read", "create", "update", "delete"],
editor: ["read", "create", "update"],
viewer: ["read"],
};
const allowed = permissions[user.role];
if (!allowed?.includes(action)) return false;
if (resource && action !== "read" && user.role !== "admin") {
return resource.ownerId === user.id;
}
return true;
}
function requirePermission(action: Action) {
return (req, res, next) => {
if (!req.user) return res.status(401).json({ error: "No autenticado" });
if (!can(req.user, action, req.resource)) {
return res.status(403).json({ error: "Prohibido" });
}
next();
};
}
app.put("/api/posts/:id", loadResource, requirePermission("update"), updatePost);
Evitar
- Verificar permisos solo en la interfaz de usuario — los atacantes llaman a tu API directamente
- Permitir el acceso a menos que se deniegue explícitamente — siempre denegar por defecto
- Usar un solo booleano
isAdmin — los roles deben ser granulares y extensibles
- Olvidar las verificaciones a nivel de recurso — "editor" no debería significar "puede editar el contenido de todos"
- Omitir la autorización en endpoints "internos" — eventualmente se vuelven públicos