first commit
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# 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
|
||||
|
||||
1. **Módulo de autenticação (`src/modules/auth/`)**
|
||||
- `POST /auth/master/login` — email + senha → valida contra
|
||||
`master_admins.senha_hash` (argon2id) → retorna access token (JWT,
|
||||
expiração curta, ex: 15 min) + refresh token (opaco, guardado como
|
||||
hash em `auth_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, usando
|
||||
`tenant_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 em
|
||||
`password_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, atualiza `senha_hash`,
|
||||
marca token como usado, revoga todos os refresh tokens ativos do
|
||||
usuário.
|
||||
|
||||
2. **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.
|
||||
|
||||
3. **Guards e decorators**
|
||||
- `@CurrentUser()` — decorator para extrair o usuário autenticado do
|
||||
request.
|
||||
- `MasterGuard` — permite apenas `tipo === 'master'`.
|
||||
- `TenantGuard` — permite apenas `tipo === 'tenant_user'`, e injeta
|
||||
`tenant_id` no contexto da request.
|
||||
- `RolesGuard` + `@Roles('tenant_admin', ...)` — restringe endpoints
|
||||
por papel dentro do tenant.
|
||||
|
||||
4. **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 executa
|
||||
`SET 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 com
|
||||
`BYPASS ROW LEVEL SECURITY` (criar essa role na migration, se ainda
|
||||
não existir, com `CREATE ROLE app_master BYPASSRLS LOGIN ...` —
|
||||
documentar isso no `.env.example` como 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_id` de outras
|
||||
formas (ex: tentando passar um `tenant_id` diferente no body de uma
|
||||
requisição — o `tenant_id` da sessão deve **sempre** vir do token,
|
||||
nunca de input do usuário).
|
||||
|
||||
5. **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`).
|
||||
|
||||
6. **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.
|
||||
|
||||
## 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
|
||||
- [ ] `MasterGuard` e `TenantGuard` bloqueiam corretamente rotas erradas
|
||||
(testar com token de tenant tentando acessar rota master e
|
||||
vice-versa)
|
||||
- [ ] `RolesGuard` bloqueia usuário `vendedor` tentando acessar rota
|
||||
restrita a `tenant_admin`
|
||||
- [ ] Teste de integração prova isolamento entre tenants via RLS (dado de
|
||||
um tenant nunca vaza para outro, mesmo forçando `tenant_id` no
|
||||
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)
|
||||
Reference in New Issue
Block a user