🛡️ Sistema de roles y permisos con JWT en PHP (admin, user, etc.) explicado fácil
Introducción
Tener login está bien.
Tener JWT también.
Pero en cuanto tu aplicación crece, aparece una necesidad clave:
👉 no todos los usuarios pueden hacer lo mismo
Ejemplos reales:
- un admin puede eliminar usuarios
- un usuario normal solo puede ver su perfil
- un staff puede gestionar contenido pero no todo
- un cliente solo puede ver sus propios datos
Y aquí es donde entra algo fundamental en backend:
👉 roles y permisos
Si no lo implementas:
- tu sistema es inseguro
- no puedes escalar
- todo el mundo puede hacer de todo
- pierdes control total
En este tutorial vas a aprender:
- qué son roles y permisos
- cómo diseñarlos correctamente
- cómo integrarlos con JWT
- cómo proteger rutas
- cómo hacerlo escalable
- errores comunes
Y todo con PHP + MySQL + JWT.
🧠 Qué son roles y permisos
🔹 Rol
Es una categoría de usuario.
Ejemplos:
- admin
- user
- staff
- cliente
🔹 Permiso
Es lo que puede hacer.
Ejemplos:
- crear usuario
- eliminar usuario
- ver reportes
- editar contenido
👉 Relación:
Un rol tiene varios permisos.
🧩 Estrategias para implementar roles
Hay 2 formas principales:
🟢 Opción 1: Roles simples (recomendado para empezar)
Guardar el rol directamente en la tabla usuarios.
ALTER TABLE usuarios ADD role VARCHAR(20) DEFAULT 'user';
Ejemplo:
usuario role Irak admin Maria user
🔵 Opción 2: Sistema avanzado (RBAC)
Tablas:
- roles
- permisos
- roles_permisos
👉 más flexible, pero más complejo
👉 Para tu caso actual:
✔ usa roles simples primero
✔ luego escalas si hace falta
🗄️ Base de datos (simple)
CREATE TABLE usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100), email VARCHAR(100) UNIQUE, password VARCHAR(255), role VARCHAR(20) DEFAULT 'user', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
🔑 Añadir el rol al JWT
Cuando haces login:
$payload = [
"user_id" => $user['id'],
"email" => $user['email'],
"role" => $user['role'],
"exp" => time() + 3600
];
👉 Esto es clave
Ahora el token sabe qué tipo de usuario es
🛡️ Middleware con roles
Ya tienes validación de JWT.
Ahora añadimos control de rol.
middleware/auth.php
<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$key = "clave_super_segura";
$headers = getallheaders();
if (!isset($headers['Authorization'])) {
http_response_code(401);
exit(json_encode(["error" => "Token requerido"]));
}
$token = str_replace("Bearer ", "", $headers['Authorization']);
try {
$decoded = JWT::decode($token, new Key($key, 'HS256'));
} catch (Exception $e) {
http_response_code(401);
exit(json_encode(["error" => "Token inválido"]));
}
🔐 Middleware de roles
Creamos función para validar rol:
<?php
function requireRole($role) {
global $decoded;
if ($decoded->role !== $role) {
http_response_code(403);
exit(json_encode(["error" => "Acceso denegado"]));
}
}
👤 Ejemplo: ruta solo admin
require 'middleware/auth.php';
requireRole('admin');
echo json_encode(["message" => "Zona admin"]);
👤 Ejemplo: múltiples roles
function requireAnyRole($roles) {
global $decoded;
if (!in_array($decoded->role, $roles)) {
http_response_code(403);
exit(json_encode(["error" => "Acceso denegado"]);
}
}
Uso:
requireAnyRole(['admin', 'staff']);
🔐 Ejemplo real de endpoints
🔹 Solo admin
DELETE /usuarios/1
🔹 Usuario normal
GET /profile
🔹 Staff
POST /posts
⚠️ Validación adicional importante
⚠️ Nunca confíes SOLO en el JWT
Porque:
- puede estar comprometido
- puede ser viejo
👉 Buen patrón:
- usar JWT para identidad
- validar datos críticos en BD si hace falta
🧠 Mejora pro: validar rol desde base de datos
Ejemplo:
$stmt = $pdo->prepare("SELECT role FROM usuarios WHERE id = ?");
$stmt->execute([$decoded->user_id]);
$user = $stmt->fetch();
if ($user['role'] !== 'admin') {
http_response_code(403);
exit("No autorizado");
}
👉 más seguro
📈 Escalabilidad: sistema de permisos (nivel pro)
Si quieres escalar:
Tablas:
roles permisos roles_permisos
Ejemplo:
role permiso admin delete_user user view_profile
👉 Esto es RBAC (Role-Based Access Control)
🧪 Caso real completo
Usuario:
{
"id": 1,
"role": "admin"
}
Token:
{
"user_id": 1,
"role": "admin"
}
API:
- valida token
- revisa rol
- permite o bloquea
⚠️ Errores comunes
❌ confiar solo en frontend
❌ no validar rol en backend
❌ usar roles sin estructura
❌ hardcodear permisos en todos lados
❌ no pensar en escalabilidad
🔐 Buenas prácticas
- usar roles claros
- centralizar validación
- usar middleware
- no repetir lógica
- validar siempre en backend
- usar logs si es sistema serio
🧠 Diferencia clave
Autenticación Autorización quién eres qué puedes hacer
JWT → autenticación
Roles → autorización
🧩 Conclusión:
Un sistema sin roles:
👉 funciona
pero no escala
Un sistema con roles:
👉 es controlado
👉 es seguro
👉 es profesional
Y esto ya es nivel backend real.