DevGuideTK
← Trilha Backend

Autorização (RBAC e ABAC)

Modelos para decidir o que cada usuário pode fazer, por papel ou por atributos.

As decisões de autorização são quatro: qual modelo usar, onde fazer a conferência, onde a política mora e como isolar os dados de cada empresa.

Qual modelo

RBAC (papel)ABAC (atributos)ReBAC (relação)
A regra diz"O financeiro pode reembolsar""Reembolsa quem é do financeiro, se o pedido for de até R$ 1.000""Edita quem é membro da equipe dona da pasta"
Pergunta que responde bemQuem pode fazer o quê, em geralPode fazer isto, neste recurso, agora?Quem tem acesso a este item, e por quê?
AuditoriaFácil: uma tabelaDifícil: depende dos dados de cada recursoMédia: segue o caminho das relações
CustoBaixoMédioAlto: um serviço e uma base de relações
Bom paraPainéis administrativos, poucos papéisRegras de negócio sobre o recurso: dono, valor, região, horárioCompartilhamento: documentos, pastas, equipes, organizações

A maioria dos sistemas de negócio fica bem com RBAC mais atributos do recurso: o papel define o alcance de cada permissão (os próprios, os da equipe, todos), e um atributo do recurso, quase sempre o dono, decide o caso. O ReBAC compensa quando os usuários compartilham itens entre si e a pergunta "quem pode ver isto?" precisa de resposta rápida.

Cuidado com a explosão de papéis

Um sinal de que o RBAC puro não basta: papéis como gerente_sp, gerente_rj, gerente_sp_leitura. Cada combinação de regra com atributo virou um papel. A saída é tirar o atributo do nome do papel e colocá-lo na regra: o papel gerente, e a regra "na região do usuário".

Onde fazer a conferência

CamadaO que confere bemO que não consegue conferir
Gateway ou proxyAutenticação, escopos do token, rotas inteiras ("só o financeiro chama /reembolsos")O dono do recurso: o gateway não sabe de quem é o pedido 981
Rota ou middlewarePermissões gerais por rotaO dono, antes de carregar o recurso
Serviço, com o recurso carregadoTudo: o usuário, o recurso e o contextoNada; é aqui que a conferência por objeto acontece
Consulta ao bancoFiltra as listagens pelo que o usuário pode verRegras complexas; vira SQL difícil de manter
Segurança por linha no bancoIsolamento entre empresas, mesmo se uma consulta esquecer o filtroRegras de negócio finas

As camadas se somam. A conferência por objeto, a que evita o IDOR, só pode acontecer depois de carregar o recurso, ou dentro da consulta que o carrega. Um middleware na entrada da rota não basta.

Para as listagens, a regra vira filtro: "os pedidos que o usuário pode ler" precisa ser traduzido em WHERE cliente_id = $1 para clientes e em nenhum filtro para o suporte. Carregar tudo e filtrar na memória funciona com poucos registros e quebra a paginação.

Onde a política mora

OpçãoComo funcionaQuando usar
No código, numa função centralUma função pode(usuario, acao, recurso) e uma tabela de alcancesO começo de quase todo sistema; uma aplicação só
Biblioteca de políticasCasbin, CASL, Pundit, as políticas do ASP.NET Core e do Spring SecurityPara organizar regras dentro de uma aplicação
Motor de políticas (OPA, Cedar)A política fica num arquivo próprio, numa linguagem de regras, avaliada por um motorVárias aplicações e linguagens com as mesmas regras; auditoria da política separada do código
Serviço de autorização (OpenFGA, SpiceDB, Permify)Um serviço guarda as relações e responde "pode?"ReBAC; compartilhamento em grande escala

O ponto em comum das quatro: um só lugar. O que dá errado é a regra espalhada em ifs pelas rotas, cada um com uma versão um pouco diferente.

O motor de políticas tem um custo que não aparece no começo. Ele precisa dos dados do recurso para decidir, e alguém tem de buscá-los e enviá-los a cada pergunta. Para regras de dono e de papel numa aplicação só, a função central no código é mais simples e igualmente segura.

Como isolar empresas

AbordagemIsolamentoCusto
Filtro em cada consultaDepende de nenhuma consulta esquecerNenhum, até o primeiro esquecimento
Filtro automático no ORM (escopos globais, filtros de consulta)Bom, mas consultas em SQL puro escapamBaixo
Segurança por linha no PostgresO banco aplica, inclusive em SQL puroConfiguração cuidadosa; ver as armadilhas abaixo
Um esquema ou um banco por empresaForteMigrações e operação multiplicadas pelo número de empresas

A segurança por linha só protege se as armadilhas medidas no nível Conceito forem evitadas:

  1. A aplicação conecta com um usuário que não é dono das tabelas, nem superusuário, nem tem BYPASSRLS. Ou a tabela usa FORCE ROW LEVEL SECURITY, que no teste fez o dono respeitar a política, mas não o superusuário.
  2. A empresa é definida com SET LOCAL, ou set_config(..., true), dentro da transação de cada pedido. Com SET, o valor ficou na conexão e vazou para o pedido seguinte.
  3. A política trata o valor ausente, com nullif sobre o current_setting.
  4. Um teste automatizado confere que uma consulta sem empresa definida devolve zero linhas.

Permissões no token ou consultadas

No tokenConsultadas a cada pedido
VelocidadeNenhuma consultaUma consulta, que um cache curto resolve
Mudança de papelSó vale quando o token vencerImediata, ou depois do cache
TamanhoO token cresce com as permissõesNão muda

Uma combinação comum: o token leva o identificador e escopos amplos e estáveis; papéis e permissões finas vêm da base, com cache de segundos ou minutos.

Resumo da decisão

  1. RBAC com atributos do recurso: papéis que definem o alcance, e o dono decide o caso. ReBAC quando o compartilhamento é central.
  2. Conferência por objeto em toda rota que recebe um identificador, depois de carregar o recurso.
  3. Uma função ou um motor de políticas, num só lugar, negando o que não estiver permitido.
  4. 404 para recursos que o usuário não pode ver; 403 para ações proibidas em recursos visíveis.
  5. Isolamento de empresas no banco com segurança por linha, sem dono da tabela e com SET LOCAL.
  6. Permissões consultadas quando mudam ou dão muito poder, em vez de presas no token.

O próximo nível mostra a mesma política nas cinco linguagens e num motor de políticas, testadas com os mesmos dez pedidos, e a segurança por linha no Postgres.

Prompts para aprofundar

Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.

  • Desenhar a autorização do meu sistema

    Quero desenhar a autorização do meu sistema.
    
    Pergunte quais são os tipos de usuário, os recursos principais, as ações sobre eles, e se há várias empresas clientes na mesma base.
    
    Depois proponha, explicando o porquê:
    1. O modelo: papéis, atributos, relações ou uma mistura.
    2. A tabela de permissões e o alcance de cada uma.
    3. Onde cada conferência acontece: gateway, rota, serviço, consulta ou banco.
    4. Como as listagens são filtradas.
    5. Como as empresas ficam isoladas.
  • Escolher onde a política mora

    Estou decidindo onde a política de autorização do meu sistema deve ficar.
    
    Pergunte quantas aplicações e linguagens precisam das mesmas regras, quão complexas elas são e se há compartilhamento entre usuários.
    
    Compare para o meu caso:
    1. Uma função central no código.
    2. Uma biblioteca de políticas da minha linguagem.
    3. Um motor de políticas, como OPA ou Cedar.
    4. Um serviço de autorização por relações, como OpenFGA ou SpiceDB.
    
    Para cada opção, explique como os dados do recurso chegam à decisão e como a política é testada.
  • Papéis no token ou consultados

    Quero decidir se as permissões dos usuários ficam dentro do token de acesso ou são consultadas a cada pedido.
    
    Pergunte como os usuários são autenticados hoje, com que frequência os papéis mudam e qual é a validade dos tokens.
    
    Explique:
    1. O que acontece quando um usuário é rebaixado e o papel está no token.
    2. O custo de consultar a cada pedido, e como um cache curto ajuda.
    3. O que faz sentido manter no token e o que buscar na base.
    4. Como revogar o acesso de alguém imediatamente.