Pular para o conteúdoPedro Farbo
Lição 13 / 2545 min

Autorização e Controle de Acesso (RBAC)

Autorização e Controle de Acesso (RBAC)

Autenticação verifica quem você é. Autorização verifica o que você pode fazer.

RBAC - Role-Based Access Control

typescript
// Roles do sistemaenum Role {  USER = 'USER',  ADMIN = 'ADMIN',} // Permissões por roleconst permissions = {  USER: ['read:products', 'create:orders', 'read:own-orders'],  ADMIN: ['read:products', 'create:products', 'update:products', 'delete:products',          'read:orders', 'update:orders', 'read:users', 'update:users'],};

Middleware de Autorização

typescript
// src/middlewares/authorize.middleware.tsimport { Request, Response, NextFunction } from 'express';import { ForbiddenError, UnauthorizedError } from '../errors'; type Role = 'USER' | 'ADMIN'; export function authorize(...allowedRoles: Role[]) {  return (req: Request, res: Response, next: NextFunction) => {    if (!req.user) {      throw new UnauthorizedError('Autenticação necessária');    }     const userRole = req.user.role as Role;     if (!allowedRoles.includes(userRole)) {      throw new ForbiddenError('Você não tem permissão para esta ação');    }     next();  };} // Verificar se é o próprio usuário ou adminexport function authorizeOwnerOrAdmin(userIdParam: string = 'id') {  return (req: Request, res: Response, next: NextFunction) => {    if (!req.user) {      throw new UnauthorizedError('Autenticação necessária');    }     const resourceUserId = req.params[userIdParam];    const isOwner = req.user.userId === resourceUserId;    const isAdmin = req.user.role === 'ADMIN';     if (!isOwner && !isAdmin) {      throw new ForbiddenError('Acesso negado');    }     next();  };}

Usando nas Rotas

typescript
// src/routes/user.routes.tsimport { Router } from 'express';import { authenticate } from '../middlewares/auth.middleware';import { authorize, authorizeOwnerOrAdmin } from '../middlewares/authorize.middleware'; const router = Router(); // Qualquer usuário autenticadorouter.get('/profile', authenticate, userController.getProfile); // Apenas adminsrouter.get('/', authenticate, authorize('ADMIN'), userController.findAll);router.delete('/:id', authenticate, authorize('ADMIN'), userController.delete); // Próprio usuário ou adminrouter.put('/:id', authenticate, authorizeOwnerOrAdmin('id'), userController.update); export default router;

Verificação em Services

typescript
// src/services/order.service.tsexport class OrderService {  async findById(orderId: string, requestingUser: { userId: string; role: string }) {    const order = await this.orderRepository.findById(orderId);     if (!order) {      throw new NotFoundError('Pedido');    }     // Verificar permissão    const isOwner = order.userId === requestingUser.userId;    const isAdmin = requestingUser.role === 'ADMIN';     if (!isOwner && !isAdmin) {      throw new ForbiddenError('Você não pode acessar este pedido');    }     return order;  }   async cancel(orderId: string, requestingUser: { userId: string; role: string }) {    const order = await this.findById(orderId, requestingUser);     // Usuários só podem cancelar pedidos pendentes    if (requestingUser.role !== 'ADMIN' && order.status !== 'PENDING') {      throw new ForbiddenError('Apenas pedidos pendentes podem ser cancelados');    }     return this.orderRepository.update(orderId, { status: 'CANCELLED' });  }}

Permissões Granulares

typescript
// src/utils/permissions.tsexport const PERMISSIONS = {  // Produtos  'products:read': ['USER', 'ADMIN'],  'products:create': ['ADMIN'],  'products:update': ['ADMIN'],  'products:delete': ['ADMIN'],   // Pedidos  'orders:read-own': ['USER', 'ADMIN'],  'orders:read-all': ['ADMIN'],  'orders:update-status': ['ADMIN'],   // Usuários  'users:read-own': ['USER', 'ADMIN'],  'users:read-all': ['ADMIN'],  'users:update-own': ['USER', 'ADMIN'],  'users:update-all': ['ADMIN'],  'users:delete': ['ADMIN'],} as const; export function hasPermission(role: string, permission: keyof typeof PERMISSIONS): boolean {  return PERMISSIONS[permission].includes(role as any);} // Middlewareexport function requirePermission(permission: keyof typeof PERMISSIONS) {  return (req: Request, res: Response, next: NextFunction) => {    if (!req.user || !hasPermission(req.user.role, permission)) {      throw new ForbiddenError('Permissão negada');    }    next();  };}

Resumo

  • ✅ RBAC para controle de acesso baseado em roles
  • ✅ Middlewares de autorização reutilizáveis
  • ✅ Verificação owner vs admin
  • ✅ Permissões granulares

Próxima aula: Upload de Arquivos! 📁

Gostou do conteúdo? Sua contribuição ajuda a manter tudo online e gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e