🛡️ 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.







🔗 Siguiente lectura recomendada: