Files
course-plat/PLANO-FIX-LOGIN-CREDENCIAIS.md
T
2026-08-31 14:10:20 -03:00

92 lines
5.2 KiB
Markdown

# Correção: login falha ("Credenciais inválidas") para alguns usuários com senha correta
## Contexto
Usuários relatam, de forma intermitente entre pessoas (não para todos), que digitam a senha
correta e recebem "Credenciais inválidas". A hipótese inicial ("será que está logando mas
mostra erro?") foi **descartada**: em `src/app/lib/userLoginAction.js` o `signIn` em caso de
sucesso lança `NEXT_REDIRECT`, que é corretamente relançado (linhas 32-39), redirecionando para
`/dispatcher`. Não existe caminho de sucesso que ainda exiba o erro. Trata-se de uma **falha real
de autenticação** (nenhuma sessão é criada).
### Causa raiz
O `username` é **gravado normalizado** mas **consultado cru**:
- Schema `src/app/models/User.js:9-10` define `trim: true` + `lowercase: true`. O Mongoose aplica
isso em todo `save`/`create`, então no banco todo username está minúsculo e sem espaços.
- Login `src/app/lib/utils/auth.js:31-32` busca com o valor cru:
`User.findOne({ username: credentials.username })`. O MongoDB faz match **case-sensitive**.
Resultado: quem cadastrou `Joao` (salvo como `joao`) e faz login digitando `Joao` gera busca por
`"Joao"` → nenhum match → `null` → "Credenciais inválidas", **sem nem comparar a senha**.
### Por que "alguns sim, outros não"
Quem digita o usuário todo em minúsculo entra; quem digita com maiúscula/espaço falha **sempre**
(consistente por usuário, não aleatório). Gatilho principal: teclado de **celular** auto-capitaliza
a primeira letra, e o input de login (`src/app/auth/login/LoginForm.jsx:31-37`) não tem
`autoCapitalize`/`autoCorrect`/`autoComplete`. Autofill com espaço final tem o mesmo efeito. Daí o
padrão "mobile reclama, desktop não".
**Observação sobre dados:** não é necessária migração de banco. Como o Mongoose já força lowercase
em toda gravação, não há usernames mixed-case armazenados — apenas a consulta precisa ser corrigida.
## Abordagem (escopo robusto)
### 1. Normalizar a consulta no provider de auth (correção central)
`src/app/lib/utils/auth.js`
- Derivar um username normalizado uma vez e usá-lo na consulta:
```js
const username = (credentials.username || "").trim().toLowerCase();
const password = credentials.password;
...
const user = await User.findOne({ username }).lean();
```
- Remover o uso duplicado de `credentials.username` na linha 32 (usar a variável já tratada).
### 2. Normalizar também no server action de login
`src/app/lib/userLoginAction.js`
- Após `formData.get("username")`, normalizar antes de validar/enviar e antes de preencher
`rawData` (para que o `defaultValue` re-exibido no form já volte normalizado):
```js
const username = (formData.get("username") || "").trim().toLowerCase();
```
- Mantém o tratamento de `NEXT_REDIRECT`/`CredentialsSignin` como está.
### 3. Endurecer o input de login contra auto-capitalização (mobile)
`src/app/auth/login/LoginForm.jsx` — no `UIInput` de `name="username"` adicionar:
`autoCapitalize="none"`, `autoCorrect="off"`, `spellCheck={false}`, `autoComplete="username"`.
- Confirmar que `src/components/ui/input.jsx` repassa `...props` (já repassa), então os atributos
fluem para o `<input>` nativo.
### 4. Alinhar a checagem de duplicado no cadastro
`src/app/lib/users/createUserAction.js:131` — a verificação `findOne({ username })` usa o valor cru
e é case-sensitive, enquanto o `User.create` grava lowercased. Normalizar o `username` logo na
leitura (linha 24) para `(formData.get("username") || "").trim().toLowerCase()`, de modo que a
checagem de duplicado, a mensagem de erro re-exibida e o valor gravado fiquem consistentes. A
validação de "sem espaços" (linha 55) continua válida.
- Aplicar a mesma normalização de leitura em `createWardUserAction.js` (criação de ward) para
manter consistência, caso ele leia username de formData da mesma forma.
## Arquivos críticos
- `src/app/lib/utils/auth.js` — fix central da consulta (CRÍTICO)
- `src/app/lib/userLoginAction.js` — normalização do input do login
- `src/app/auth/login/LoginForm.jsx` — atributos anti auto-capitalize
- `src/app/lib/users/createUserAction.js` — consistência na checagem/gravação
- `src/app/lib/users/createWardUserAction.js` — mesma consistência
- (referência, sem alteração) `src/app/models/User.js`, `src/components/ui/input.jsx`
## Verificação
1. **Repro do bug (antes do fix):** com um usuário existente (ex.: `joao`), tentar login digitando
`Joao` ou `joao ` (com espaço) → deve dar "Credenciais inválidas".
2. **Depois do fix:**
- Login com `Joao`, `JOAO`, ` joao `, `joao` → todos devem autenticar e redirecionar para
`/dispatcher`.
- Senha errada → continua "Credenciais inválidas" (regressão de segurança garantida).
- Usuário inexistente → "Credenciais inválidas".
3. **Mobile:** abrir `/auth/login` em viewport mobile / dispositivo e confirmar que o campo Usuário
não auto-capitaliza a primeira letra.
4. **Cadastro:** registrar `Maria`; conferir no banco que foi salvo como `maria`; tentar cadastrar
`maria` de novo → "Nome de usuario ja cadastrado".
5. Rodar a app localmente (`npm run dev`) e exercitar os fluxos acima; rodar a suíte de testes se
existir.