O modelo RBAC (Role-Based Access Control) é uma abordagem amplamente utilizada em sistemas corporativos para gerenciar permissões de forma flexível.
O Que é RBAC?
RBAC se baseia na ideia de associar permissões a papéis, e não diretamente a usuários. A hierarquia é:
Usuário → Papel → Permissão
Em vez de atribuir permissões individuais a cada usuário, você atribui um ou mais papéis a um usuário. Cada papel possui um conjunto definido de permissões. Alterar os papéis de um usuário efetivamente modifica seu conjunto de permissões.
Modelo de Permissão de Três Níveis
Um sistema RBAC comum pode ser estruturado em três níveis:
- Operador/Usuário: A entidade que acessa o sistema.
- Papel: Um agrupamento de permissões.
- Permissão:
- Menu: Define o acesso a páginas ou seções específicas da interface.
- Botão: Controla ações específicas dentro de uma página (ex: editar, excluir).
- Aplicação: Determina o acesso a diferentes produtos ou módulos do sistema.
Estrutura de Tabelas Essenciais
Para implementar essa estrutura, são necessárias tabelas de associação:
-- Associação entre Papéis e Menus
CREATE TABLE ROLE_MENU_ASSOCIATION (
ROLE_ID VARCHAR(32) NOT NULL,
MENU_ID VARCHAR(32) NOT NULL,
PRIMARY KEY (ROLE_ID, MENU_ID)
);
-- Associação entre Papéis e Botões
CREATE TABLE ROLE_BUTTON_ASSOCIATION (
ROLE_ID VARCHAR(32) NOT NULL,
BUTTON_ID VARCHAR(32) NOT NULL,
PRIMARY KEY (ROLE_ID, BUTTON_ID)
);
-- Associação entre Usuários e Papéis
CREATE TABLE OPERATOR_ROLE_ASSOCIATION (
OPERATOR_ID VARCHAR(32) NOT NULL,
ROLE_ID VARCHAR(32) NOT NULL,
PRIMARY KEY (OPERATOR_ID, ROLE_ID)
);
Rotas Dinâmicas no Frontend
Uma abordagem engenhosa para o frontend é a criação dinâmica de rotas, evitando a exposição de rotas não autorizadas no código-fonte.
Abordagem Tradicional: Rotas são definidas estaticamente no frontend e o acesso é controlado por permissões, o que pode expor a estrutura completa do sistema.
Abordagem Dinâmica:
- Após o login do usuário, o frontend solicita a árvore de menus permitidos.
- O backend retorna apenas os menus aos quais o usuário tem acesso.
- O frontend utiliza essas informações para adicionar rotas dinamicamente em tempo de execução (usando
router.addRouteem frameworks como Vue.js). - O usuário só consegue navegar para rotas que foram explicitamente autorizadas pelo backend.
// Exemplo de lógica em Vue.js (router/index.js)
async function loadDynamicRoutes() {
const allowedMenus = await apiService.fetchUserMenus(); // Chama API para obter menus permitidos
allowedMenus.forEach(menu => {
if (menu.componentPath) { // Verifica se há um componente associado
router.addRoute('mainLayout', { // 'mainLayout' é o nome da rota pai
path: menu.routePath,
name: menu.menuIdentifier,
component: () => import(`../views/${menu.componentPath}.vue`)
});
}
});
}
// Chamado após o login bem-sucedido
await loadDynamicRoutes();
router.push('/home'); // Redireciona para a página inicial
Permissões em Nível de Botão
Para um controle mais granular, as permissões podem se estender a botões específicos dentro de uma interface:
<!-- Exemplo de diretiva de permissão no frontend (Vue.js) -->
<el-button
v-has-permission="'resource:delete'"
type="danger"
@click="handleResourceDeletion"
>
Excluir Recurso
</el-button>
A diretiva personalizada verifica se o usuário possui a permisssão associada ao código do botão:
// Implementação da diretiva v-has-permission
app.directive('has-permission', {
mounted(el, binding) {
const requiredPermission = binding.value;
// Verifica se a permissão está no conjunto de permissões do usuário (obtido do backend)
const userHasPermission = store.getters.userPermissions.includes(requiredPermission);
if (!userHasPermission) {
el.style.display = 'none'; // Oculta o botão se não tiver permissão
}
}
});
Fluxo de Autenticação Detalhado
- Usuário insere credenciais (usuário e senha).
- Frontend: Aplica transformações na senha (ex: Hashing com SHA1 e MD5).
- Frontend: Criptografa o corpo da requisição usando AES e RSA.
- Frontend: Envia requisição POST para o endpoint de login (
/auth/login). - Backend: Descriptografa a requisição, verifica as credenciais no banco de dados.
- Backend: Gera um tokan JWT e o armazena em cache (ex: Redis), usando o token como chave.
- Backend: Retorna o token JWT e informações básicas do usuário.
- Frontend: Armazena o token JWT (ex: em
localStorage). - Frontend: Chama a API para obter a lista de menus permitidos para configurar rotas dinâmicas.
- Frontend: Chama a API para obter a lista de permissões de botões.
- Frontend: Injeta as rotas dinamicamente e redireciona o usuário para a página inicial.
Vantagens e Desvantagens
Benefícios:
- Gerenciamento Centralizado: Alterações de permissão em um papel refletem imediatamente para todos os usuários associados.
- Segurança do Frontend: Rotas não autorizadas não são expostas no código-fonte do cliente.
- Controle Granular: Permissões em nível de botão garantem dupla validação (interface e API).
- Suporte Multi-Aplicação: Um único sistema de permissões pode gerenciar acesso a múltiplos produtos ou módulos.
Desventagens:
- Complexidade: Mais complexo de implementar do que um controle simples baseado em
if (isAdmin). - Tempo de Implementação Inicial: Requer um investimento inicial maior de tempo para a configuração.