Cómo modificar el password broker de la recuperación de contraseñas de laravel
Contenido
Si estas trabajando con la laravel 6, el recuperar una contraseña ya no requiere que se hagan cambios en el Password Broker si cambias las validaciones en el controller, es decir que ya no tienes que hacer nada tío!, esto ya quedo solucionado.
Laravel 6
Hace unos días me encontré con esta pregunta en un grupo de Laravel.
Hola. Estoy intentando cambiar las reglas de validación del password cuando se produce la recuperación de contraseña. Tengo entendido que hay que sobre escribir el método rules del trait ResetsPasswords que usa ResetPasswordController. Copio y pego el método del trait en mi controlador y lo único que hago es cambiar el atributo min de 8 (que por defecto en el trait a 6:
La parte de código que viene en la pregunta es la siguiente.
/** * Get the password reset validation rules. * * @return array */ protected function rules() { return [ 'token' => 'required', 'email' => 'required|email', 'password' => 'required|confirmed|min:8', ]; }
Si cambias la validación min:8, vas a notar que de todas formas no puedes cambiar la contraseña de un usuario, porque sin importar que pongas menor a 8 en la validación, Seguirás recibiendo un mensaje de error y eso genera un poco de confusión sobre todo si estas comenzando a usar Laravel.
Muy posiblemente te preguntes, si no es la regla de validación entonces que es lo que sucede y el misterio se resuelve revisando el componente que se encarga de hacer el cambio de contraseña la clase Password Broker.
Este componente valida que las contraseñas tenga una longitud mínima de 8 caracteres, si no se cumple regresa un error en la validación.
/** * Determine if the passwords are valid for the request. * * @param array $credentials * @return bool */ protected function validatePasswordWithDefaults(array $credentials) { [$password, $confirm] = [ $credentials['password'], $credentials['password_confirmation'], ]; return $password === $confirm && mb_strlen($password) >= 8; }
Esto se hace por seguridad y en realidad no recomiendo que le metas mano, pero a veces se tiene que buscar la manera de acceder al Password Broker para personalizarlo, el detalle es que esto no es tan sencillo.
Así que me tome el tiempo de escribir esto, para explicar como puedes hacer cambios en esta parte de Laravel.
Análisis.
Cuando usas la recuperación de contraseñas de Laravel, se utilizan dos controladores: El ForgotPasswordController y el ResetPasswordController
Ambos controladores ocupan el Password Broker para hacer su tarea.
De tal forma que, cuando llamamos a este método.
/** * Get the broker to be used during password reset. * * @return \Illuminate\Contracts\Auth\PasswordBroker */ public function broker() { return Password::broker(); }
Regresa la siguiente estructura de objetos.
Es decir, el Facade Password te regresa un PasswordBrokerManager que es un Factory, que crea instancias de PasswordBroker y que se almacena cada una de ellas en el arreglo $brokers[].
El asunto es que este Manager tiene un pequeño detalle.
/** * Resolve the given broker. * * @param string $name * @return \Illuminate\Contracts\Auth\PasswordBroker * * @throws \InvalidArgumentException */ protected function resolve($name) { $config = $this->getConfig($name); if (is_null($config)) { throw new InvalidArgumentException("Password resetter [{$name}] is not defined."); } // The password broker uses a token repository to validate tokens and send user // password e-mails, as well as validating that password reset process as an // aggregate service of sorts providing a convenient interface for resets. return new PasswordBroker( $this->createTokenRepository($config), $this->app['auth']->createUserProvider($config['provider'] ?? null) ); }
Observa la linea 18 del código; no existe forma de extender a otras implementaciones de PassworBroker!
Así que, si quieres cambiar la regla de la que hemos estado hablando desde el principio, requieres dos cosas, extender el PasswordBrokerManager y el PasswordBroke
Así que, vamos a ver como podemos hacer esto.
Implementación
Aquí viene la parte divertida, para realizar los cambios requerimos extender la clase PasswordBrokerManager, la clase PasswordBroker, decirle a Laravel que reconozca nuestros cambios mediante el uso del ServiceProvider .
Extender la clase PasswordBroker
Debido a que solo vamos a sobreescribir un método, solo tienes que extender de la clase original.
use Illuminate\Auth\Passwords\PasswordBroker; class CustomPasswordBroker extends PasswordBroker { /** * Determine if the passwords are valid for the request. * * @param array $credentials * @return bool */ protected function validatePasswordWithDefaults(array $credentials) { [$password, $confirm] = [ $credentials['password'], $credentials['password_confirmation'], ]; return $password === $confirm && mb_strlen($password) >= 6; } }
Observa que la validación ahora acepta una longitud mayor o igual a 6.
Extender la clase PasswordBrokerManager
Aquí vamos a extender y sobreescribir el método resolve.
use Illuminate\Auth\Passwords\PasswordBrokerManager; use InvalidArgumentException; class CustomPasswordBrokerManager extends PasswordBrokerManager { /** * Resolve the given broker. * * @param string $name * @return \Illuminate\Contracts\Auth\PasswordBroker * * @throws \InvalidArgumentException */ protected function resolve($name) { $config = $this->getConfig($name); if (is_null($config)) { throw new InvalidArgumentException("Password resetter [{$name}] is not defined."); } // The password broker uses a token repository to validate tokens and send user // password e-mails, as well as validating that password reset process as an // aggregate service of sorts providing a convenient interface for resets. return new CustomPasswordBroker( $this->createTokenRepository($config), $this->app['auth']->createUserProvider($config['provider'] ?? null) ); } }
Ahora este método regresa nuestra versión del PasswordBroker.
Crear clase CustomPasswordResetServiceProvider
Esta clase se encargara de decirle al Contenedor de dependencias, que ahora tiene que ocupar nuestra implementación en lugar de la original.
use Illuminate\Support\ServiceProvider; use App\Password\CustomPasswordBrokerManager; use Illuminate\Contracts\Support\DeferrableProvider; class CustomPasswordResetServiceProvider extends ServiceProvider implements DeferrableProvider { /** * Register the service provider. * * @return void */ public function register() { $this->registerPasswordBroker(); } /** * Register the password broker instance. * * @return void */ protected function registerPasswordBroker() { $this->app->singleton('auth.password', function ($app) { return new CustomPasswordBrokerManager($app); }); $this->app->bind('auth.password.broker', function ($app) { return $app->make('auth.password')->broker(); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return ['auth.password', 'auth.password.broker']; } }
Finalmente edita el archivo config/app.php y cambia esta linea del arreglo providers
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Por nuestra implementación.
App\Providers\CustomPasswordResetServiceProvider::class,
Y eso es todo, la siguiente vez que uses la recuperación de contraseñas ya no tendrás problemas con la validación.
Si tienes alguna duda deja tu comentario y recuerda compartir este artículo!