1. Seguridad
  2. Restablecimiento de contraseñas

Introducción

La mayoría de las aplicaciones web proporcionan una forma para que los usuarios restablezcan sus contraseñas olvidadas. En lugar de obligarte a implementar esto manualmente para cada aplicación que crees, Laravel proporciona servicios convenientes para enviar enlaces de restablecimiento de contraseñas y restablecer contraseñas de forma segura.

Nota ¿Quieres empezar rápido? Instala un kit de inicio de aplicación de Laravel en una nueva aplicación Laravel. Los kits de inicio de Laravel se encargarán de la estructura de todo tu sistema de autenticación, incluyendo restablecer contraseñas olvidadas.

Preparación del modelo

Antes de utilizar las funciones de restablecimiento de contraseña de Laravel, el modelo App\Models\User de tu aplicación debe utilizar el rasgo Illuminate\Notifications\Notifiable. Por lo general, este rasgo ya se incluye en el modelo App\Models\User predeterminado que se crea con nuevas aplicaciones Laravel.

A continuación, verifica que tu modelo App\Models\User implemente el contrato Illuminate\Contracts\Auth\CanResetPassword. El modelo App\Models\User incluido con el framework ya implementa esta interfaz y utiliza el rasgo Illuminate\Auth\Passwords\CanResetPassword para incluir los métodos necesarios para implementar la interfaz.

Preparación de la base de datos

Se debe crear una tabla para almacenar los tokens de restablecimiento de contraseña de tu aplicación. La migración para esta tabla está incluida en la aplicación Laravel por defecto, así que solo necesitas migrar tu base de datos para crear esta tabla:

php artisan migrate

Configuración de hosts de confianza

Por defecto, Laravel responderá a todas las solicitudes que reciba, independientemente del contenido del encabezado Host de la solicitud HTTP. Además, el valor del encabezado Host se utilizará al generar URL absolutas a tu aplicación durante una solicitud web.

Por lo general, debes configurar tu servidor web, como Nginx o Apache, para enviar solo las solicitudes a tu aplicación que coincidan con un nombre de host dado. Sin embargo, si no tienes la capacidad de personalizar tu servidor web directamente y necesitas indicarle a Laravel que solo responda a ciertos nombres de host, puedes hacerlo habilitando el middleware App\Http\Middleware\TrustHosts para tu aplicación. Esto es especialmente importante cuando tu aplicación ofrece funcionalidad de restablecimiento de contraseña.

Para obtener más información sobre este middleware, consulta la documentación del middleware TrustHosts.

Enrutamiento

Para implementar correctamente el soporte para permitir a los usuarios restablecer sus contraseñas, necesitaremos definir varias rutas. Primero, necesitaremos un par de rutas para manejar la solicitud de un enlace de restablecimiento de contraseña a través de su dirección de correo electrónico. En segundo lugar, necesitaremos un par de rutas para manejar el restablecimiento real de la contraseña una vez que el usuario visite el enlace de restablecimiento de contraseña que se le envió por correo electrónico y complete el formulario de restablecimiento de contraseña.

Solicitando el enlace de restablecimiento de contraseña

El formulario de solicitud de enlace de restablecimiento de contraseña

Primero, definiremos las rutas necesarias para solicitar enlaces de restablecimiento de contraseña. Para comenzar, definiremos una ruta que devuelva una vista con el formulario de solicitud de enlace de restablecimiento de contraseña:

Route::get('/forgot-password', function () {
return view('auth.forgot-password');
})->middleware('guest')->name('password.request');

La vista devuelta por esta ruta debe tener un formulario que contenga un campo email, que permitirá al usuario solicitar un enlace de restablecimiento de contraseña para una dirección de correo electrónico determinada.

Manejo del envío del formulario

A continuación, definiremos una ruta que maneje la solicitud de envío del formulario desde la vista de "olvidó su contraseña". Esta ruta será responsable de validar la dirección de correo electrónico y enviar la solicitud de restablecimiento de contraseña al usuario correspondiente:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
 
Route::post('/forgot-password', function (Request $request) {
$request->validate(['email' => 'required|email']);
 
$status = Password::sendResetLink(
$request->only('email')
);
 
return $status === Password::RESET_LINK_SENT
? back()->with(['status' => __($status)])
: back()->withErrors(['email' => __($status)]);
})->middleware('guest')->name('password.email');

Antes de continuar, examinemos esta ruta con más detalle. Primero, se valida el atributo email de la solicitud. A continuación, utilizaremos el "password broker" incorporado de Laravel (a través de la fachada Password) para enviar un enlace de restablecimiento de contraseña al usuario. El password broker se encargará de recuperar al usuario por el campo proporcionado (en este caso, la dirección de correo electrónico) y enviar al usuario un enlace de restablecimiento de contraseña a través del sistema de notificaciones incorporado de Laravel.

El método sendResetLink devuelve un "status" que puede traducirse utilizando las ayudas de localización de Laravel para mostrar un mensaje amigable al usuario sobre el estado de su solicitud. La traducción del estado de restablecimiento de contraseña se determina por el archivo de idioma lang/{lang}/passwords.php de tu aplicación. Hay una entrada para cada valor posible del estado en el archivo de idioma passwords.

Nota Por defecto, el esqueleto de la aplicación Laravel no incluye el directorio lang. Si deseas personalizar los archivos de idioma de Laravel, puedes publicarlos mediante el comando Artisan lang:publish.

Es posible que te preguntes cómo Laravel sabe cómo recuperar el registro de usuario de la base de datos de tu aplicación al llamar al método sendResetLink de la fachada Password. El password broker de Laravel utiliza los "proveedores de usuarios" de tu sistema de autenticación para recuperar registros de la base de datos. El proveedor de usuarios utilizado por el password broker se configura dentro del array de configuración passwords de tu archivo de configuración config/auth.php. Para obtener más información sobre cómo escribir proveedores de usuarios personalizados, consulta la documentación de autenticación.

Nota Cuando implementas manualmente el restablecimiento de contraseñas, debes definir tú mismo el contenido de las vistas y rutas. Si deseas un andamiaje que incluya toda la lógica necesaria de autenticación y verificación, echa un vistazo a los kits de inicio de aplicación de Laravel.

Restableciendo la contraseña

El formulario de restablecimiento de contraseña

A continuación, definiremos las rutas necesarias para restablecer realmente la contraseña una vez que el usuario haga clic en el enlace de restablecimiento de contraseña que se le ha enviado por correo electrónico y proporcione una nueva contraseña. Primero, definamos la ruta que mostrará el formulario de restablecimiento de contraseña que se muestra cuando el usuario hace clic en el enlace de restablecimiento de contraseña. Esta ruta recibirá un parámetro token que usaremos más tarde para verificar la solicitud de restablecimiento de contraseña:

Route::get('/reset-password/{token}', function (string $token) {
return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');

La vista que devuelve esta ruta debe mostrar un formulario que contenga un campo email, un campo password, un campo password_confirmation y un campo oculto token, que debe contener el valor del secreto $token recibido por nuestra ruta.

Manejo del envío del formulario

Por supuesto, necesitamos definir una ruta para manejar realmente el envío del formulario de restablecimiento de contraseña. Esta ruta será responsable de validar la solicitud entrante y actualizar la contraseña del usuario en la base de datos:

use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
 
Route::post('/reset-password', function (Request $request) {
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:8|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();
 
event(new PasswordReset($user));
}
);
 
return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withErrors(['email' => [__($status)]]);
})->middleware('guest')->name('password.update');

Antes de continuar, examinemos esta ruta con más detalle. Primero, se validan los atributos token, email y password de la solicitud. A continuación, utilizaremos el "password broker" incorporado de Laravel (a través de la fachada Password) para validar las credenciales de la solicitud de restablecimiento de contraseña.

Si el token, la dirección de correo electrónico y la contraseña proporcionados al password broker son válidos, se invocará el cierre pasado al método reset. Dentro de este cierre, que recibe la instancia del usuario y la contraseña en texto plano proporcionada al formulario de restablecimiento de contraseña, podemos actualizar la contraseña del usuario en la base de datos.

El método reset devuelve un "status" que puede traducirse utilizando las ayudas de localización de Laravel para mostrar un mensaje amigable al usuario sobre el estado de su solicitud. La traducción del estado de restablecimiento de contraseña se determina por el archivo de idioma lang/{lang}/passwords.php de tu aplicación. Hay una entrada para cada valor posible del estado en el archivo de idioma passwords. Si tu aplicación no contiene un directorio lang, puedes crearlo con el comando Artisan lang:publish.

Antes de continuar, es posible que te preguntes cómo Laravel sabe cómo recuperar el registro de usuario de la base de datos de tu aplicación al llamar al método reset de la fachada Password. El password broker de Laravel utiliza los "proveedores de usuarios" de tu sistema de autenticación para recuperar registros de la base de datos. El proveedor de usuarios utilizado por el password broker se configura dentro del array de configuración passwords de tu archivo de configuración config/auth.php. Para obtener más información sobre cómo escribir proveedores de usuarios personalizados, consulta la documentación de autenticación.

Eliminación de tokens caducados

Los tokens de restablecimiento de contraseña que han caducado seguirán presentes en tu base de datos. Sin embargo, puedes eliminar fácilmente estos registros usando el comando Artisan auth:clear-resets:

php artisan auth:clear-resets

Si deseas automatizar este proceso, considera agregar el comando a la programación de tu aplicación:

$schedule->command('auth:clear-resets')->everyFifteenMinutes();

Personalización

Personalización del enlace de restablecimiento

Puedes personalizar fácilmente la URL del enlace de restablecimiento de contraseña utilizando el método createUrlUsing proporcionado por la clase de notificación ResetPassword. Este método acepta un cierre que recibe la instancia del usuario que está recibiendo la notificación y el token del enlace de restablecimiento de contraseña. Normalmente, debes llamar a este método desde el método boot del proveedor de servicios App\Providers\AuthServiceProvider de tu aplicación:

use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
 
/**
* Registrar cualquier servicio de autenticación / autorización.
*/
public function boot(): void
{
ResetPassword::createUrlUsing(function (User $user, string $token) {
return 'https://example.com/reset-password?token='.$token;
});
}

Personalización del correo electrónico de restablecimiento

Puedes modificar fácilmente la clase de notificación utilizada para enviar el enlace de restablecimiento de contraseña al usuario. Para empezar, sobrescribe el método sendPasswordResetNotification en tu modelo App\Models\User. Dentro de este método, puedes enviar la notificación usando cualquier clase de notificación de tu propia creación. El $token de restablecimiento de contraseña es el primer argumento recibido por el método. Puedes usar este $token para construir la URL de restablecimiento de contraseña que prefieras y enviar tu notificación al usuario:

use App\Notifications\ResetPasswordNotification;
 
/**
* Enviar una notificación de restablecimiento de contraseña al usuario.
*
* @param string $token
*/
public function sendPasswordResetNotification($token): void
{
$url = 'https://example.com/reset-password?token='.$token;
 
$this->notify(new ResetPasswordNotification($url));
}