Login por matrícula no Laravel: busca, limite de tentativas e recuperação de senha
Troque o e-mail pela matrícula no login do Laravel sem quebrar o resto: coluna única, Auth::attempt com a chave certa, limite por matrícula e um caminho real para recuperar acesso.
O almoxarifado da Distribuidora Ponte pediu para a equipe entrar com a matrícula do crachá, não com e-mail. O desenvolvedor trocou o rótulo do campo, renomeou o name do input e mudou uma linha no controller. O login funcionou. Na semana seguinte, a operadora Rita esqueceu a senha, digitou a matrícula 004187 na tela de recuperação e nada aconteceu: a tela ainda procurava um e-mail, e o "Rita" da conta tinha o e-mail genérico do setor, que ninguém lê.
A resposta curta: no Laravel, trocar o identificador de login é mexer em quatro lugares juntos — a coluna no banco, a chamada a Auth::attempt, a chave do limite de tentativas e o fluxo de recuperação de senha. Se só o primeiro muda, o login entra e a recuperação de acesso fica quebrada. Este guia mostra a implementação; o raciocínio geral, válido para qualquer framework, está em trocar o campo de login de e-mail para matrícula.
Por que não é só trocar o rótulo
O e-mail cumpre dois papéis ao mesmo tempo: identifica a conta e é o canal para falar com a pessoa. Quando você troca o identificador para matrícula, separa esses papéis. A matrícula identifica, mas não recebe mensagem. Tudo que dependia do e-mail como canal — link de redefinição de senha, aviso de login suspeito, confirmação de troca — precisa de outro destino.
Há também uma diferença de risco. E-mails são difíceis de adivinhar em sequência; matrículas costumam ser números sequenciais. Quem tenta entrar sabe que 004186 e 004188 provavelmente existem. Isso torna o limite de tentativas e a mensagem de erro genérica ainda mais importantes do que no login por e-mail.
Por fim, se a mesma aplicação tem clientes entrando com e-mail e equipe entrando com matrícula, são duas portas. Misturar as duas no mesmo formulário com um if costuma acabar em sessão compartilhada; a separação por guard está em dois logins no Laravel.
Como implementar o login por matrícula
- Crie a coluna com índice único e normalize o formato antes de gravar.
- Decida o canal de recuperação: e-mail de contato cadastrado à parte ou atendimento presencial.
- Troque a chave em
Auth::attemptdeemailparamatricula. - Troque a chave do limite de tentativas, que no código gerado pelos kits iniciais também usa o e-mail.
- Mantenha a mensagem de erro genérica, igual para matrícula inexistente e senha errada.
- Ajuste a recuperação de senha para buscar pela matrícula e enviar ao canal decidido no passo 2.
A migração
Schema::table('funcionarios', function (Blueprint $table) {
$table->string('matricula', 20)->unique()->after('id');
$table->string('email_contato')->nullable();
$table->boolean('ativo')->default(true);
});
A matrícula é string, não inteiro. "004187" com zeros à esquerda é um identificador, não uma quantidade; guardado como número, vira 4187 e a pessoa que digita os zeros não entra. O índice único garante que a busca encontre no máximo uma conta e deixa a consulta rápida.
Normalizar antes de buscar
Crachás impressos com espaço ("004 187"), letras maiúsculas e minúsculas em matrículas alfanuméricas e zeros que alguém omite são as fontes clássicas de "a senha está certa e não entra". Escolha uma forma canônica e aplique tanto no cadastro quanto no login:
function normalizarMatricula(string $valor): string
{
return strtoupper(preg_replace('/\s+/', '', $valor));
}
Se a regra da empresa é que matrículas sempre têm seis dígitos, você pode completar com zeros à esquerda aqui também. O importante é que o cadastro e o login passem pela mesma função. Espaços invisíveis colados de planilha são outro clássico, descrito em espaço em branco que quebra o login.
O controller de login
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Validation\ValidationException;
public function store(Request $request)
{
$dados = $request->validate([
'matricula' => ['required', 'string', 'max:20'],
'password' => ['required', 'string'],
]);
$matricula = normalizarMatricula($dados['matricula']);
$chave = 'login-equipe:' . $matricula . '|' . $request->ip();
if (RateLimiter::tooManyAttempts($chave, 5)) {
$segundos = RateLimiter::availableIn($chave);
throw ValidationException::withMessages([
'matricula' => 'Muitas tentativas. Tente novamente em ' . $segundos . ' segundos.',
]);
}
$credenciais = [
'matricula' => $matricula,
'password' => $dados['password'],
'ativo' => true,
];
if (! Auth::guard('equipe')->attempt($credenciais, $request->boolean('lembrar'))) {
RateLimiter::hit($chave);
throw ValidationException::withMessages([
'matricula' => 'Matrícula ou senha incorretas.',
]);
}
RateLimiter::clear($chave);
$request->session()->regenerate();
return redirect()->intended('/painel');
}
O provider Eloquent do Laravel usa todas as chaves do array de credenciais, exceto a senha, como condição de busca. Por isso 'matricula' e 'ativo' viram um WHERE, e a senha é conferida contra o hash. Funcionário desligado com ativo = false não entra, sem código extra.
Se o projeto nasceu de um kit inicial como o Breeze, o login fica numa classe de request com um método que chama Auth::attempt com e-mail e outro que monta a chave do limite de tentativas também com o e-mail. Troque os dois. Esquecer o segundo faz o limite contar tentativas por um campo vazio, e o bloqueio deixa de funcionar ou bloqueia todo mundo junto.
A mensagem de erro
"Matrícula não encontrada" e "senha incorreta" como mensagens diferentes ensinam a quem está testando quais matrículas existem. Como matrícula é sequencial, a lista inteira sai em minutos. Use a mesma mensagem para os dois casos, como explica login que diz "usuário não existe".
Recuperação de senha com matrícula
O broker de senhas do Laravel busca o usuário pelas credenciais que você passa, grava o token associado ao valor de getEmailForPasswordReset() e envia uma notificação por e-mail. Por padrão, tanto esse método quanto o roteamento da notificação usam a coluna email. Dá para aproveitar o mecanismo: busque pela matrícula e aponte os dois para o e-mail de contato.
// No model Funcionario
public function getEmailForPasswordReset()
{
return $this->email_contato;
}
public function routeNotificationForMail($notification)
{
return $this->email_contato;
}
// No controller de "esqueci a senha"
$status = Password::broker('funcionarios')->sendResetLink([
'matricula' => normalizarMatricula($request->input('matricula')),
]);
return back()->with('status', 'Se a matrícula estiver cadastrada com um e-mail de contato, enviamos as instruções.');
Três cuidados. A resposta é sempre a mesma, exista ou não a matrícula. O formulário de redefinição gerado pelos kits espera o e-mail no link e no formulário, então revise essa tela para trabalhar com o identificador que você escolheu. E o broker funcionarios precisa estar configurado em config/auth.php apontando para o provider da equipe.
Quando parte da equipe não tem e-mail nenhum, não invente um. O caminho honesto é a redefinição assistida: um supervisor autenticado gera um link de uso único, válido por pouco tempo, e entrega pessoalmente. Fica registrado quem gerou e quando. Isso é mais seguro do que um "e-mail do setor" que dez pessoas leem.
Erros comuns
- Guardar matrícula como inteiro. Zeros à esquerda somem e quem digita "004187" não entra.
- Trocar o
attempte esquecer a chave do limite de tentativas. O bloqueio por excesso de tentativas para de funcionar ou bloqueia todos. - Mensagens diferentes para matrícula inexistente e senha errada. Matrícula sequencial vira lista de contas válidas.
- Manter a recuperação procurando e-mail. A pessoa pede o link e nada chega; a próxima ligação é para o suporte.
- Cadastrar e-mail genérico do setor como canal de recuperação. Qualquer colega pode redefinir a senha de outro.
- Normalizar só no login. O cadastro grava "004 187" e o login procura "004187".
Checklist
- A coluna
matriculaé texto, única e indexada. - Cadastro e login passam pela mesma função de normalização.
Auth::attemptusa a matrícula e filtra contas inativas.- O limite de tentativas usa a matrícula normalizada na chave.
- A mensagem de erro é igual para matrícula inexistente e senha errada.
- A recuperação busca pela matrícula e envia a um canal individual.
- Quem não tem e-mail tem um processo de redefinição assistida com registro.
Pegue uma conta de teste da equipe, peça a recuperação de senha usando só a matrícula e acompanhe: em qual caixa de entrada o link chega, e quem mais lê essa caixa?
Referência: https://blog.impulso.network/autenticacao-em-laravel-modificando-a-validacao-das-credenciais/