5.5 KiB
5.5 KiB
Etapa 2/8 — Autenticação, Autorização e Row Level Security
Contexto do projeto
Continuação do SeConectai Vendas (CRM/vendas multi-tenant). A Etapa 1
já entregou: projeto NestJS + Docker Compose + Postgres/Prisma com o
schema completo migrado (incluindo as tabelas master_admins,
tenant_users, auth_refresh_tokens, password_reset_tokens,
login_attempts e as policies de RLS).
Existem dois tipos de usuário:
- master_admins: você, dono da plataforma — acesso a todos os tenants.
- tenant_users: usuários de cada tenant (cliente seu), com papéis
(
tenant_admin,vendedor,financeiro,visualizador), restritos aos próprios dados via RLS.
Objetivo desta etapa
Implementar login, emissão/renovação de tokens, reset de senha,
mecanismo de definição do tenant_id da sessão no Postgres (RLS) e
proteção contra força bruta — para ambos os tipos de usuário.
Tarefas
-
Módulo de autenticação (
src/modules/auth/)POST /auth/master/login— email + senha → valida contramaster_admins.senha_hash(argon2id) → retorna access token (JWT, expiração curta, ex: 15 min) + refresh token (opaco, guardado como hash emauth_refresh_tokens, expiração longa, ex: 30 dias).POST /auth/tenant/login— email + senha + (implícito) tenant resolvido pelo email único dentro do tenant → mesma lógica, usandotenant_users.POST /auth/refresh— recebe refresh token, valida hash e expiração/revogação, rotaciona (invalida o antigo, emite um novo) e retorna novo par de tokens.POST /auth/logout— revoga o refresh token atual.POST /auth/password/forgot— gera token empassword_reset_tokens(hash, expiração curta, ex: 1h) e dispara e-mail (por ora, apenas logar o link/token no console — o envio real de e-mail é de uma etapa futura).POST /auth/password/reset— valida token, atualizasenha_hash, marca token como usado, revoga todos os refresh tokens ativos do usuário.
-
JWT payload
- Incluir no access token:
sub(id do usuário),tipo(master|tenant_user),tenant_id(null para master),role(para tenant_user). - Implementar
JwtStrategy(Passport) validando assinatura e expiração.
- Incluir no access token:
-
Guards e decorators
@CurrentUser()— decorator para extrair o usuário autenticado do request.MasterGuard— permite apenastipo === 'master'.TenantGuard— permite apenastipo === 'tenant_user', e injetatenant_idno contexto da request.RolesGuard+@Roles('tenant_admin', ...)— restringe endpoints por papel dentro do tenant.
-
Aplicação do RLS via Prisma
- Implementar um mecanismo (middleware/interceptor do Nest, executado
por request) que, para requests autenticadas como
tenant_user, abre uma transação Prisma e executaSET LOCAL app.current_tenant_id = '<tenant_id>'antes de qualquer query — garantindo que a policy de RLS do Postgres filtre os dados automaticamente. - Para requests como
master, usar uma conexão/role de banco comBYPASS ROW LEVEL SECURITY(criar essa role na migration, se ainda não existir, comCREATE ROLE app_master BYPASSRLS LOGIN ...— documentar isso no.env.examplecomo uma segunda connection string opcional,DATABASE_URL_MASTER). - Escrever um teste de integração que prove o isolamento: criar dois
tenants, um usuário em cada, confirmar que a query de um nunca
retorna dado do outro mesmo manipulando o
tenant_idde outras formas (ex: tentando passar umtenant_iddiferente no body de uma requisição — otenant_idda sessão deve sempre vir do token, nunca de input do usuário).
- Implementar um mecanismo (middleware/interceptor do Nest, executado
por request) que, para requests autenticadas como
-
Proteção contra força bruta
- Toda tentativa de login (sucesso ou falha) grava em
login_attempts. - Após N tentativas falhas (configurável, ex: 5) para o mesmo e-mail em uma janela de tempo (ex: 15 min), bloquear novas tentativas com 429 e mensagem clara, mesmo que a senha esteja correta.
- Rate limiting geral no endpoint de login (ex:
@nestjs/throttler).
- Toda tentativa de login (sucesso ou falha) grava em
-
Segurança de senha
- Hash com argon2id (biblioteca
argon2), parâmetros de custo documentados no código. - Validação de força mínima da senha no cadastro/reset (tamanho mínimo, não permitir senhas triviais).
- Refresh tokens e reset tokens nunca armazenados em texto puro — sempre hash (ex: sha256) antes de gravar no banco.
- Hash com argon2id (biblioteca
Critérios de aceite
- Login master e login tenant funcionam e retornam access+refresh token válidos
- Refresh token rotaciona corretamente; token antigo usado após rotação é rejeitado
- Logout revoga o refresh token
- Fluxo de esqueci minha senha gera token, valida expiração/uso único
MasterGuardeTenantGuardbloqueiam corretamente rotas erradas (testar com token de tenant tentando acessar rota master e vice-versa)RolesGuardbloqueia usuáriovendedortentando acessar rota restrita atenant_admin- Teste de integração prova isolamento entre tenants via RLS (dado de
um tenant nunca vaza para outro, mesmo forçando
tenant_idno payload da requisição) - Após 5 tentativas de login falhas, novas tentativas são bloqueadas temporariamente
- Todas as senhas no banco estão como hash argon2id (nenhuma em texto puro em nenhuma tabela)