Pular para o conteúdo principal

Autenticação e Segurança

Stack de autenticação

TecnologiaFunção
ASP.NET Core IdentityGerenciamento de usuários, senhas (hash PBKDF2), roles e claims
JWT Bearer TokensAutenticação stateless — TenantId e Role viajam nos claims
Refresh TokensArmazenados no banco, renovam o JWT sem novo login

Por que JWT e não sessão?

O projeto é um monolito modular, mas cada módulo roda sem estado compartilhado. JWT é stateless: o token carrega tudo que o servidor precisa para autorizar a requisição, sem consultar banco ou cache para cada chamada.

Alternativas consideradas:

OpçãoPor que não usar
Session (cookie)Requer estado no servidor — dificulta escalabilidade horizontal
Auth externo puro (Auth0, Keycloak)Complexidade e custo desnecessários para o MVP
API Key simplesSem suporte a roles, expiração ou refresh

Fluxo completo

1. POST /auth/login
↓ Identity valida e-mail + senha (PBKDF2)
↓ Gera JWT com claims: sub, tenantId, role, exp (15 min)
↓ Gera Refresh Token (opaque, 30 dias) → salva no banco
↓ Retorna { accessToken, refreshToken }

2. Requisições autenticadas
Authorization: Bearer <accessToken>
↓ Middleware valida assinatura + exp
↓ Claims populam ITenantContext e ICurrentUser
↓ Handler executa com contexto correto

3. POST /auth/refresh
↓ Recebe refreshToken
↓ Valida no banco (existe? expirou? foi revogado?)
↓ Emite novo accessToken + novo refreshToken (rotação)
↓ Invalida o refresh token anterior

4. POST /auth/logout
↓ Revoga o refreshToken no banco
↓ accessToken expira naturalmente (não pode ser revogado — 15 min é curto o suficiente)

Claims no JWT

{
"sub": "user-guid",
"tenantId": "tenant-guid",
"role": "TenantAdmin",
"exp": 1714000000
}

O middleware de cada requisição lê esses claims e popula:

// ITenantContext — lido pelo HasQueryFilter do EF Core
public string CurrentTenantId => _httpContextAccessor.HttpContext
.User.FindFirstValue("tenantId");

// ICurrentUser — lido pelos handlers para auditoria
public string UserId => _httpContextAccessor.HttpContext
.User.FindFirstValue(ClaimTypes.NameIdentifier);

Hierarquia de roles

RoleEscopoPermissões
SuperAdminGlobalCria/gerencia tenants, altera planos, acesso total
TenantAdminPor tenantGerencia usuários, vendedores e configurações da empresa
UserPor tenantOperação do CRM dentro das permissões definidas pelo TenantAdmin

Regras de segurança críticas

  • Refresh Token é rotacionado a cada uso — se um token vazado for usado, o legítimo é invalidado e a sessão é encerrada.
  • accessToken dura 15 minutos — janela curta limita o impacto de um token interceptado.
  • Logout revoga o refreshToken no banco imediatamente.
  • Último TenantAdmin não pode ser removido — bloqueado no domain layer.
  • Tentativas de login devem ter rate limiting (Redis via Upstash) para evitar brute force.

Fonte: ASP.NET Core Identity — Microsoft Learn | JWT Bearer — Microsoft Learn