Este post é a continuação do nosso tutorial sobre Autenticação de APIs no Laravel com Sanctum. Se você ainda não conferiu, recomendo dar uma olhada também: Autenticação de APIs no Laravel com Sanctum.
Para aqueles que preferem conteúdo em vídeo, este tutorial também está disponível no meu canal do YouTube. Confira o vídeo completo aqui: https://youtu.be/YzehJJzuVeI
A redefinição de senha é uma funcionalidade essencial em qualquer API. No Laravel, podemos implementá-la de forma simples e segura utilizando o sistema de notificações e o pacote de recuperação de senha do próprio framework.
Utilizando o pacote de recuperação de senha do Laravel, já temos pronto toda a lógica para redefinição de senha com as melhores práticas de segurança. Nosso trabalho será apenas criar as rotas e implementar os métodos no controlador de autenticação.
Vamos ver como implementar essa funcionalidade passo a passo.
⚠️ Este tutorial foi feito utilizando o Laravel 11, que é a versão atual no momento. Se você estiver usando uma versão diferente, pode ser necessário adaptar alguns passos.
1. Criando as Rotas de Redefinição de Senha
No arquivo routes/api.php
, defina as rotas para solicitar a redefinição e para redefinir a senha:
use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;
Route::post('/auth/forgot-password', [AuthController::class, 'forgotPassword'])->name('auth.forgot-password');
Route::post('/auth/reset-password', [AuthController::class, 'resetPassword'])->name('auth.reset-password');
A rota forgotPassword
é responsável por enviar o link de redefinição de senha para o e-mail do usuário.
A rota resetPassword
é responsável por redefinir a senha do usuário.
2. Implementando os Métodos no AuthController
Agora, no app/Http/Controllers/AuthController.php
, adicione os métodos responsáveis pelo envio do link de redefinição e pela atualização da senha.
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
class AuthController extends Controller
{
public function forgotPassword(Request $request): JsonResponse
{
$request->validate([
'email' => 'required|email',
]);
Password::sendResetLink($request->only('email'));
return response()->json(status: Response::HTTP_OK);
}
public function resetPassword(Request $request): JsonResponse
{
$request->validate([
'token' => 'required|string',
'email' => 'required|email',
'password' => 'required|min:6|confirmed',
]);
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function (User $user, string $password) {
$user->forceFill([
'password' => Hash::make($password)
])->setRememberToken(Str::random(60));
$user->save();
}
);
if ($status == Password::PASSWORD_RESET) {
return response()->json(status: Response::HTTP_OK);
}
return response()->json(['message' => 'Erro ao redefinir a senha'], status: Response::HTTP_BAD_REQUEST);
}
}
O método forgotPassword
recebe o e-mail do usuário como argumento e utiliza a classe Password
do Laravel para enviar o link de redefinição de senha.
O método resetPassword
recebe o token, o e-mail e a nova senha como argumentos e utiliza a classe Password
do Laravel para redefinir a senha do usuário.
3. Criando a Notificação Personalizada de Redefinição de Senha
No Laravel, podemos personalizar completamente a notificação de redefinição de senha criando uma classe de notificação própria.
Antes de criar a classe de notificação, vamos gerar um template de e-mail (Mailable) para redefinição de senha.
Gerando o template de e-mail
Para gerar essa classe, utilize o seguinte comando artisan:
php artisan make:mail ResetPasswordNotificationMail
O conteúdo da nossa classe ResetPasswordNotificationMail
ficará assim:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ResetPasswordNotificationMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(public string $url)
{
//
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Redefinição de Senha',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
view: 'emails.password-reset',
with: ['url' => $this->url],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
A classe ResetPasswordNotificationMail
recebe o link de redefinição de senha como argumento e utiliza o template password-reset.blade.php
para exibir o link.
O template de e-mail de redefinição pode ser personalizado conforme necessário. Aqui está um modelo simples para o arquivo resources/views/emails/password-reset.blade.php
:
<div style="font-family: Arial, sans-serif">
<p>Clique no link abaixo para redefinir sua senha:</p>
<a href="{{ $url }}">{{ $url }}</a>
</div>
Este é um template minimalista que reflete minha preferência pessoal, mas pode ser ajustado conforme necessário para atender às necessidades do projeto.
Gerando a classe de notificação
Para gerar a classe de notificação, utilize o seguinte comando artisan:
php artisan make:notification ResetPasswordNotification
O conteúdo da nossa classe ResetPasswordNotification
ficará assim:
namespace App\Notifications;
use App\Mail\ResetPasswordNotificationMail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class ResetPasswordNotification extends Notification
{
use Queueable;
public function __construct(public string $url)
{
//
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): ResetPasswordNotificationMail
{
return (new ResetPasswordNotificationMail($this->url))
->to($notifiable->email);
}
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}
A classe ResetPasswordNotification
é responsável por enviar o e-mail de redefinição de senha. Ela recebe o link de redefinição de senha como argumento e utiliza a classe ResetPasswordNotificationMail
que criamos anteriormente para enviar o e-mail.
4. Enviando a Notificação personalizada de Redefinição de Senha
Para que o Laravel use nossa notificação personalizada, precisamos sobrescrever o método sendPasswordResetNotification
no modelo User
.
No arquivo app/Models/User.php
, sobrescrevemos o método sendPasswordResetNotification
para enviar nossa própria notificação personalizada:
public function sendPasswordResetNotification($token): void
{
$url = config('services.frontend.url') . '/reset-password?token=' . $token . '&email=' . $this->email;
$this->notify(new ResetPasswordNotification($url));
}
Dessa forma, o Laravel usará nossa notificação personalizada para enviar o e-mail de redefinição de senha.
O link de redefinição de senha é gerado a partir da URL do frontend que também recebe o token e o e-mail do usuário como parâmetros. Com essas informações, o frontend é responsável por receber a nova senha do usuário e fazer a chamada para o nosso endpoint de redefinição de senha /api/auth/reset-password
com os parâmetros necessários (token, email e nova senha).
Por que usar a URL do frontend?
Nossa aplicação Laravel serve apenas como API, enquanto o usuário final interage com o frontend separado. Por isso, ao gerar o link de redefinição de senha, direcionamos o usuário para o frontend, onde ele poderá inserir uma nova senha.
Essa URL do frontend poderia ser recebida como argumento caso a api suportasse mais de um frontend. Nesse exemplo estamos usando apenas um frontend, então prefiro armazenar a url do frontend nas variáveis de ambiente do Laravel (.env
) e referenciá-la na configuração services.frontend.url
.
5. Testando a Funcionalidade
Agora que tudo está configurado, podemos testar as rotas com o Postman ou curl
.
Solicitar a redefinição de senha:
curl -X POST http://localhost/api/auth/forgot-password -H "Content-Type: application/json" -d '{"email": "[email protected]"}'
Um e-mail de redefinição de senha será enviado para o usuário com um link para redefinir a senha.
Redefinir a senha:
curl -X POST http://localhost/api/auth/reset-password -H "Content-Type: application/json" -d '{"token": "SEU_TOKEN", "email": "[email protected]", "password": "novasenha", "password_confirmation": "novasenha"}'
Se a senha for redefinida com sucesso, a API retornará um status 200 OK e o usuário poderá logar com a nova senha no endpoint /api/auth/login
.
Com isso, sua API agora suporta redefinição de senha de forma segura e eficiente!
Para mais informações sobre boas práticas na redefinição de senha no Laravel, recomendo dar uma olhada na Documentação oficial do Laravel sobre redefinição de senha.
Se ainda não conferiu o tutorial anterior, recomendo dar uma olhada para entender a base da autenticação: Autenticação de APIs no Laravel com Sanctum.