Initial commit
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user