Pular para conteúdo

Solução 10 - Controle de Acesso (RBAC) 🛡️

Navegação

← Exercício 10 | Próxima Solução →

🟢 Respostas Fáceis

1. Conceito de Role no RBAC

Resposta 1

Role (Papel) no sistema RBAC:

**Role** é um **conjunto de permissões** agrupadas que define **o que um usuário pode fazer** no sistema.

**🎭 Analogia de Empresa:**
```mermaid
graph TD
    A[👤 João Silva] --> B[🏷️ ROLE: Gerente]
    B --> C[📖 Permissões:]
    C --> D[✅ Ler relatórios]
    C --> E[✅ Aprovar despesas]
    C --> F[✅ Gerenciar equipe]
    C --> G[❌ Acessar financeiro]
```

**📋 Exemplos Práticos de Roles:**

| Role | Permissões Típicas | Descrição |
|------|-------------------|-----------|
| **USER** | `read_profile`, `edit_profile` | Usuário comum do sistema |
| **EDITOR** | `create_content`, `edit_content`, `delete_own_content` | Criador de conteúdo |
| **MODERATOR** | `approve_content`, `delete_any_content`, `ban_users` | Moderador da comunidade |
| **ADMIN** | `manage_users`, `system_settings`, `view_logs` | Administrador do sistema |
| **SUPER_ADMIN** | `*` (todas as permissões) | Acesso total ao sistema |

**🔧 Implementação em Código:**
```javascript
// Definição de Roles
const ROLES = {
    USER: {
        name: 'user',
        permissions: ['profile.read', 'profile.edit']
    },
    EDITOR: {
        name: 'editor',
        permissions: ['profile.read', 'profile.edit', 'content.create', 'content.edit']
    },
    ADMIN: {
        name: 'admin',
        permissions: ['*'] // Todas as permissões
    }
};

// Usuário com Role
const usuario = {
    id: 123,
    nome: "João Silva",
    role: ROLES.EDITOR,
    permissions: ROLES.EDITOR.permissions
};
```

2. Status Code para Acesso Negado

Resposta 2

Status Code apropriado: 403 Forbidden

**Justificativa:**
- **401 Unauthorized**: "Quem é você?" - Não está logado/autenticado
- **403 Forbidden**: "Sei quem você é, mas você não pode fazer isso" - Logado mas sem permissão

**🎯 Usuário comum tentando área admin:**
```http
GET /admin/dashboard HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
    "erro": "Acesso negado",
    "message": "Você não tem permissão para acessar esta área",
    "required_role": "admin",
    "your_role": "user"
}
```

🟡 Respostas Médias

3. Diferença entre 401 e 403

Resposta 3

Diferença fundamental 401 vs 403:

| Aspecto | **401 Unauthorized** | **403 Forbidden** |
|---------|---------------------|-------------------|
| **Significado** | **"Quem é você?"** | **"Sei quem você é, mas não pode"** |
| **Causa** | **Não autenticado** | **Sem autorização** |
| **Token JWT** | **Ausente/inválido/expirado** | **Válido, mas role insuficiente** |
| **Ação do Client** | **Ir para login** | **Mostrar "Acesso negado"** |
| **Redirecionamento** | **✅ Sim → /login** | **❌ Não** |

**🔄 Fluxos Comparativos:**
```mermaid
flowchart TD
    A[Request com Token] --> B{Token válido?}

    B -->|Não| C[❌ 401 Unauthorized]
    B -->|Sim| D{Tem permissão?}

    C --> E[🔄 Redirecionar para /login]
    D -->|Não| F[❌ 403 Forbidden]
    D -->|Sim| G[✅ 200 OK + Conteúdo]
    F --> H[🚫 Mostrar "Acesso Negado"]

    style C fill:#ff6b6b
    style F fill:#ffa726
    style G fill:#81c784
```

**💻 Implementação no Frontend:**
```javascript
// Interceptor de resposta
axios.interceptors.response.use(
    response => response,
    error => {
        if (error.response?.status === 401) {
            // ✅ Redirecionar para login
            localStorage.removeItem('authToken');
            window.location.href = '/login';
            toast.error('Sessão expirada. Faça login novamente.');
        } else if (error.response?.status === 403) {
            // ❌ Não redirecionar, apenas informar
            toast.error('Você não tem permissão para esta ação.');
            // Usuário fica na mesma página
        }
        return Promise.reject(error);
    }
);
```

4. Middlewares para Rota Admin

Resposta 4

Dois middlewares para /admin/dashboard:

**1º `verificarAutenticacao` → 2º `verificarAutorizacao`**

```javascript
// ✅ Ordem correta
app.get('/admin/dashboard',
    verificarAutenticacao,    // 1º: Verifica se está logado
    verificarAutorizacao(['ADMIN']), // 2º: Verifica se é admin
    dashboardController      // 3º: Controller final
);
```

**🔧 Implementação dos Middlewares:**
```javascript
// 1º MIDDLEWARE - Autenticação
function verificarAutenticacao(req, res, next) {
    const token = req.headers.authorization?.replace('Bearer ', '');

    if (!token) {
        return res.status(401).json({
            erro: "Token não fornecido",
            action: "redirect_login"
        });
    }

    try {
        const payload = jwt.verify(token, process.env.JWT_SECRET);
        req.user = payload; // Adiciona usuário na request
        next(); // ✅ Passa para próximo middleware
    } catch (error) {
        return res.status(401).json({
            erro: "Token inválido",
            action: "redirect_login"
        });
    }
}

// 2º MIDDLEWARE - Autorização
function verificarAutorizacao(rolesPermitidas) {
    return (req, res, next) => {
        // req.user já foi definido pelo middleware anterior
        const userRole = req.user.role;

        if (!rolesPermitidas.includes(userRole)) {
            return res.status(403).json({
                erro: "Acesso negado",
                required_roles: rolesPermitidas,
                your_role: userRole
            });
        }

        next(); // ✅ Passa para controller
    };
}
```

**⚡ Por que essa ordem é importante:**
```mermaid
sequenceDiagram
    participant C as Cliente
    participant A as Auth Middleware
    participant R as Role Middleware
    participant D as Dashboard Controller

    C->>+A: GET /admin/dashboard

    alt ❌ Sem token
        A-->>-C: 401 - Vá fazer login
    else ✅ Token válido
        A->>+R: Usuário autenticado

        alt ❌ Não é admin
            R-->>-C: 403 - Sem permissão
        else ✅ É admin
            R->>+D: Usuário autorizado
            D-->>-C: 200 - Dashboard data
        end
    end
```

🔴 Resposta Desafio

5. Sistema Hierárquico de Roles

Resposta 5

Implementação de Hierarquia RBAC:

**a) Função autorizar() com múltiplas roles:**
```javascript
function autorizar(rolesPermitidas) {
    return (req, res, next) => {
        const userRole = req.user.role;

        // ✅ Verificar se user tem QUALQUER uma das roles
        if (rolesPermitidas.includes(userRole)) {
            return next(); // Autorizado
        }

        return res.status(403).json({
            erro: "Acesso negado",
            required_roles: rolesPermitidas,
            your_role: userRole
        });
    };
}

// Exemplos de uso:
app.get('/editor/posts',
    verificarAutenticacao,
    autorizar(['EDITOR', 'ADMIN']),  // EDITOR OU ADMIN podem acessar
    postsController
);
```

**b) Sistema Hierárquico Inteligente:**
```javascript
// ✅ Sistema de hierarquia de roles
const ROLE_HIERARCHY = {
    'USER': 1,
    'EDITOR': 2,
    'MODERATOR': 3,
    'ADMIN': 4,
    'SUPER_ADMIN': 5
};

function temPermissaoHierarquica(userRole, roleMinima) {
    const nivelUsuario = ROLE_HIERARCHY[userRole] || 0;
    const nivelMinimo = ROLE_HIERARCHY[roleMinima] || 0;

    return nivelUsuario >= nivelMinimo;
}

function autorizarHierarquico(roleMinima) {
    return (req, res, next) => {
        const userRole = req.user.role;

        if (temPermissaoHierarquica(userRole, roleMinima)) {
            return next(); // ✅ Autorizado
        }

        return res.status(403).json({
            erro: "Nível de acesso insuficiente",
            required_minimum: roleMinima,
            your_role: userRole,
            hierarchy: ROLE_HIERARCHY
        });
    };
}

// Uso simplificado:
app.get('/user/profile',
    verificarAutenticacao,
    autorizarHierarquico('USER'),     // USER+ pode acessar
    profileController
);

app.get('/editor/dashboard',
    verificarAutenticacao,
    autorizarHierarquico('EDITOR'),   // EDITOR+ pode acessar (inclui ADMIN)
    editorController
);

app.get('/admin/settings',
    verificarAutenticacao,
    autorizarHierarquico('ADMIN'),    // Apenas ADMIN+ pode acessar
    adminController
);
```

**c) Sistema Avançado com Permissões Granulares:**
```javascript
// Sistema híbrido: Roles + Permissions
const ROLE_DEFINITIONS = {
    'USER': {
        level: 1,
        permissions: ['profile.read', 'profile.edit']
    },
    'EDITOR': {
        level: 2,
        inherits: ['USER'], // Herda permissões de USER
        permissions: ['content.create', 'content.edit', 'content.delete_own']
    },
    'MODERATOR': {
        level: 3,
        inherits: ['EDITOR'],
        permissions: ['content.moderate', 'users.suspend']
    },
    'ADMIN': {
        level: 4,
        inherits: ['MODERATOR'],
        permissions: ['users.manage', 'system.settings', 'logs.view']
    },
    'SUPER_ADMIN': {
        level: 5,
        permissions: ['*'] // Todas as permissões
    }
};

class PermissionManager {
    static obterPermissoesCompletas(role) {
        const roleDef = ROLE_DEFINITIONS[role];
        if (!roleDef) return [];

        let permissions = [...roleDef.permissions];

        // Herdar permissões das roles pai
        if (roleDef.inherits) {
            for (const parentRole of roleDef.inherits) {
                permissions = [
                    ...permissions,
                    ...this.obterPermissoesCompletas(parentRole)
                ];
            }
        }

        return [...new Set(permissions)]; // Remove duplicatas
    }

    static temPermissao(userRole, permissaoRequerida) {
        const permissions = this.obterPermissoesCompletas(userRole);

        // Super admin tem tudo
        if (permissions.includes('*')) return true;

        // Verificar permissão específica
        return permissions.includes(permissaoRequerida);
    }
}

// Middleware baseado em permissões
function requerPermissao(permissao) {
    return (req, res, next) => {
        const userRole = req.user.role;

        if (PermissionManager.temPermissao(userRole, permissao)) {
            return next();
        }

        return res.status(403).json({
            erro: "Permissão insuficiente",
            required_permission: permissao,
            your_role: userRole,
            your_permissions: PermissionManager.obterPermissoesCompletas(userRole)
        });
    };
}

// Uso granular:
app.delete('/posts/:id',
    verificarAutenticacao,
    requerPermissao('content.delete_own'), // Permissão específica
    deletePostController
);
```

**🎯 Vantagens da Abordagem Centralizada:**

```mermaid
graph TD
    A[Sistema Centralizado] --> B[Manutenibilidade]
    A --> C[Consistência]
    A --> D[Auditabilidade]
    A --> E[Escalabilidade]

    B --> F["Uma mudança de role afeta todo o sistema"]
    C --> G["Regras iguais em toda aplicação"]
    D --> H["Logs centralizados de acesso"]
    E --> I["Fácil adicionar novas roles/permissions"]

    style A fill:#e3f2fd
    style B fill:#c8e6c9
    style C fill:#c8e6c9
    style D fill:#c8e6c9
    style E fill:#c8e6c9
```

**✅ Benefícios Específicos:**

1. **DRY (Don't Repeat Yourself)**:
   ```javascript
   // ❌ Sem hierarquia - repetitivo
   app.get('/users', autorizar(['USER', 'EDITOR', 'ADMIN']));
   app.get('/posts', autorizar(['USER', 'EDITOR', 'ADMIN']));
   app.get('/comments', autorizar(['USER', 'EDITOR', 'ADMIN']));

   // ✅ Com hierarquia - simples
   app.get('/users', autorizarHierarquico('USER'));
   app.get('/posts', autorizarHierarquico('USER'));
   app.get('/comments', autorizarHierarquico('USER'));
   ```

2. **Mudanças Dinâmicas**:
   ```javascript
   // Promover usuário afeta automaticamente todas as routes
   await User.update({ role: 'ADMIN' }, { where: { id: userId } });
   // ✅ Usuário agora tem acesso a TODAS as rotas de níveis inferiores
   ```

3. **Auditoria e Compliance**:
   ```javascript
   function logAcesso(req, res, next) {
       const { user, originalUrl, method } = req;

       console.log(`[ACCESS] ${user.role} ${user.name} → ${method} ${originalUrl}`);

       // Para compliance (SOX, GDPR, etc.)
       auditLogger.info({
           userId: user.id,
           action: `${method} ${originalUrl}`,
           role: user.role,
           timestamp: new Date(),
           ip: req.ip
       });

       next();
   }
   ```

!!! tip "Dicas para Próximos Estudos" - Implemente Permission-based Access Control (PBAC) para controle granular - Configure Dynamic Role Assignment baseado em contexto - Use Policy-based Authorization para regras complexas - Mantenha audit logs detalhados para compliance

Navegação

← Exercício 10 | Próxima Solução →