verified_user 10. Middleware de Autenticação
Middleware é o guardião da sua API. É um código que executa antes de cada endpoint protegido, verificando se o usuário está autenticado e autorizado. Sem middleware, você teria que copiar a mesma lógica de validação JWT em todos os arquivos, criando código duplicado e pontos de falha.
Um middleware profissional faz quatro coisas: extrai o token JWT do header Authorization,
valida sua assinatura e expiração, decodifica o payload para obter o ID do usuário e
retorna 401 Unauthorized se qualquer etapa falhar. Ele também deve implementar
rate limiting, logging de acessos e blacklist de tokens revogados.
Nesta seção final, você aprenderá a construir um sistema completo de middleware com autorização baseada em roles (RBAC), cache de permissões, rate limiting por IP e integração transparente com todos os endpoints CRUD criados nas seções anteriores.
route Arquitetura de Middleware
┌─────────────────────────────────────────────────────────────────┐
│ REQUISIÇÃO DO FRONTEND │
│ POST /api/posts/create │
│ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ MIDDLEWARE 1: CORS Headers │
│ ✅ Verifica origem permitida │
│ ✅ Adiciona headers Access-Control-* │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ MIDDLEWARE 2: Rate Limiting │
│ ✅ Verifica tentativas por IP (max 100/min) │
│ ❌ Se exceder → 429 Too Many Requests │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ MIDDLEWARE 3: JWT Verification │
│ 1. Extrai token do header Authorization │
│ 2. Valida assinatura HMAC │
│ 3. Verifica expiração (exp) │
│ 4. Decodifica payload → user_id │
│ ❌ Se inválido → 401 Unauthorized │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ MIDDLEWARE 4: Authorization (RBAC) │
│ ✅ Verifica role do usuário (user/admin/moderator) │
│ ✅ Checa permissões específicas (can_create_posts) │
│ ❌ Se sem permissão → 403 Forbidden │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ENDPOINT (posts/create.php) │
│ 🎯 Lógica de negócio executa aqui │
│ 📊 user_id está disponível via $GLOBALS['user_id'] │
└─────────────────────────────────────────────────────────────────┘
code Implementando Middleware JWT
false,
'message' => 'Token não fornecido',
'code' => 'NO_TOKEN'
]);
exit;
}
// 2. VALIDAR FORMATO "Bearer TOKEN"
if (!preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
http_response_code(401);
echo json_encode([
'success' => false,
'message' => 'Formato de token inválido (use: Bearer TOKEN)',
'code' => 'INVALID_FORMAT'
]);
exit;
}
$token = $matches[1];
// 3. VALIDAR JWT
$decoded = validateJWT($token);
if (!$decoded) {
http_response_code(401);
echo json_encode([
'success' => false,
'message' => 'Token inválido ou expirado',
'code' => 'INVALID_TOKEN'
]);
exit;
}
// 4. EXTRAIR USER_ID
$userId = $decoded->sub ?? null;
if (!$userId) {
http_response_code(401);
echo json_encode([
'success' => false,
'message' => 'Token não contém user_id',
'code' => 'MALFORMED_TOKEN'
]);
exit;
}
// 5. VERIFICAR SE USUÁRIO AINDA EXISTE E ESTÁ ATIVO
global $pdo;
$stmt = $pdo->prepare('SELECT id, active FROM users WHERE id = ?');
$stmt->execute([$userId]);
$user = $stmt->fetch();
if (!$user || !$user['active']) {
http_response_code(401);
echo json_encode([
'success' => false,
'message' => 'Usuário inativo ou não encontrado',
'code' => 'USER_INACTIVE'
]);
exit;
}
// 6. (OPCIONAL) VERIFICAR BLACKLIST DE TOKENS REVOGADOS
$stmt = $pdo->prepare('
SELECT id FROM token_blacklist
WHERE token = ? AND expires_at > NOW()
');
$stmt->execute([hash('sha256', $token)]);
if ($stmt->fetch()) {
http_response_code(401);
echo json_encode([
'success' => false,
'message' => 'Token foi revogado (logout forçado)',
'code' => 'TOKEN_REVOKED'
]);
exit;
}
// 7. LOG DE ACESSO (opcional, para auditoria)
try {
$pdo->prepare('
INSERT INTO access_logs (user_id, endpoint, method, ip, user_agent, created_at)
VALUES (?, ?, ?, ?, ?, NOW())
')->execute([
$userId,
$_SERVER['REQUEST_URI'] ?? '',
$_SERVER['REQUEST_METHOD'] ?? '',
$_SERVER['REMOTE_ADDR'] ?? '',
$_SERVER['HTTP_USER_AGENT'] ?? ''
]);
} catch (Exception $e) {
// Log, mas não bloquear requisição
error_log("Access log error: " . $e->getMessage());
}
// ✅ AUTENTICAÇÃO BEM-SUCEDIDA
return $userId;
}
/**
* Middleware de autorização baseada em role
*
* @param array $allowedRoles - Roles permitidas ['admin', 'moderator']
* @return void - Encerra com 403 se não autorizado
*/
function requireRole($allowedRoles = []) {
$userId = verifyAuth(); // Garante autenticação primeiro
global $pdo;
$stmt = $pdo->prepare('SELECT role FROM users WHERE id = ?');
$stmt->execute([$userId]);
$userRole = $stmt->fetchColumn();
if (!in_array($userRole, $allowedRoles)) {
http_response_code(403);
echo json_encode([
'success' => false,
'message' => 'Sem permissão para acessar este recurso',
'code' => 'FORBIDDEN',
'required_roles' => $allowedRoles,
'your_role' => $userRole
]);
exit;
}
}
?>
- Extração e validação de token JWT
- Verificação de usuário ativo no banco
- Blacklist de tokens revogados
- Log de acessos para auditoria
- Autorização baseada em roles (RBAC)
integration_instructions Usando o Middleware nos Endpoints
lock_open Endpoint Público
query('
SELECT * FROM posts
WHERE status = "published"
LIMIT 10
');
echo json_encode($stmt->fetchAll());
?>
lock Endpoint Protegido
'Post criado',
'user_id' => $userId
]);
?>
admin_panel_settings Endpoint Admin-Only
query('SELECT * FROM users');
echo json_encode($stmt->fetchAll());
?>
speed Rate Limiting - Prevenir Abuso
= 100) {
http_response_code(429); // Too Many Requests
echo json_encode([
'success' => false,
'message' => 'Muitas requisições. Tente novamente em 1 minuto.',
'code' => 'RATE_LIMIT_EXCEEDED',
'retry_after' => 60
]);
header('Retry-After: 60');
exit;
}
apcu_inc($key, 1, $success, 60); // Incrementa e expira em 60s
}
}
// USO: Chamar no início de cada endpoint
checkRateLimit();
?>
logout Revogação de Tokens (Logout)
exp);
$pdo->prepare('
INSERT INTO token_blacklist (token, user_id, expires_at, created_at)
VALUES (?, ?, ?, NOW())
')->execute([$tokenHash, $userId, $expiresAt]);
echo json_encode([
'success' => true,
'message' => 'Logout realizado com sucesso'
]);
}
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Erro ao fazer logout']);
}
?>
-- Tabela de blacklist de tokens
CREATE TABLE token_blacklist (
id INT AUTO_INCREMENT PRIMARY KEY,
token CHAR(64) NOT NULL, -- SHA256 hash
user_id INT NOT NULL,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_token (token),
INDEX idx_expires (expires_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Job de limpeza (executar diariamente)
DELETE FROM token_blacklist WHERE expires_at < NOW();
shield Permissões Granulares (RBAC Avançado)
prepare('SELECT role FROM users WHERE id = ?');
$stmt->execute([$userId]);
$role = $stmt->fetchColumn();
// Definir permissões por role (pode vir do banco)
$rolePermissions = [
'admin' => ['*'], // Todas permissões
'moderator' => [
'posts.create', 'posts.update', 'posts.delete',
'comments.delete', 'users.view'
],
'user' => [
'posts.create', 'posts.update-own', 'posts.delete-own',
'comments.create'
]
];
$userPermissions = $rolePermissions[$role] ?? [];
// Verificar se tem permissão (ou wildcard *)
return in_array('*', $userPermissions) || in_array($permission, $userPermissions);
}
/**
* Middleware que requer permissão específica
*/
function requirePermission($permission) {
if (!hasPermission($permission)) {
http_response_code(403);
echo json_encode([
'success' => false,
'message' => "Sem permissão: $permission",
'code' => 'PERMISSION_DENIED'
]);
exit;
}
}
// USO:
// api/posts/create.php
requirePermission('posts.create');
?>
Admin
Permissões:
• Todas (*)
• Gerenciar usuários
• Configurações sistema
Moderator
Permissões:
• Editar/deletar posts
• Moderar comentários
• Ver usuários
User
Permissões:
• Criar posts
• Editar próprios posts
• Comentar
summarize Checklist Final de Segurança
✅ Backend (PHP)
- ☑️ PDO com prepared statements
- ☑️ Validação de todos inputs
- ☑️ Sanitização de dados
- ☑️ JWT com secret forte (256+ bits)
- ☑️ CORS configurado corretamente
- ☑️ HTTPS obrigatório em produção
- ☑️ Rate limiting implementado
- ☑️ Logs de auditoria
- ☑️ Backups automáticos
✅ Frontend (React)
- ☑️ Token em localStorage (ou httpOnly cookie)
- ☑️ Axios interceptors para token
- ☑️ Refresh automático em 401
- ☑️ Validação client-side (UX)
- ☑️ Sanitização XSS (DOMPurify)
- ☑️ Variáveis .env (não commitar)
- ☑️ CSP headers configurados
- ☑️ Confirmação em deletes
- ☑️ Loading states adequados
Você agora possui conhecimento profissional para construir aplicações full-stack seguras e escaláveis. Este artigo cobriu todos os fundamentos essenciais:
🚀 Próximos Passos: Deploy em produção, CI/CD, testes automatizados, Docker, Kubernetes...