Cómo implementar la verificación de contraseñas mediante la solicitud de formulario de Laravel

Introducción
Las solicitudes de formulario de Laravel son clases especiales que amplían la funcionalidad de las clases de solicitud normales, lo que permite funciones de validación avanzadas. Las solicitudes de formulario también ayudan a mantener las acciones de tu controlador mucho más limpias, porque puedes mover toda tu lógica de validación a la clase de solicitud de formulario. Otro beneficio es que te permite filtrar las solicitudes antes de que lleguen a las acciones de tu controlador.
En esta guía, implementaremos un paso de verificación de contraseña para solicitar que un usuario confirme su contraseña antes de acceder a un área de administración. Esta práctica funciona como una doble verificación y le brinda a su aplicación una capa adicional de seguridad.
Prerrequisitos
Para continuar con esta guía, necesitará una aplicación Laravel 5.6+ que funcione y que tenga configurada la autenticación de Laravel integrada. Consulte la documentación oficial para obtener detalles sobre cómo configurarla.
Paso 1: creación de la vista
Comenzaremos configurando la página de edición del perfil de un usuario.
Al momento de escribir este tutorial, artisan
la utilidad de comando no genera vistas, por lo que necesitaremos crear la vista manualmente.
Crea el archivo resources/views/profile/edit.blade.php
y agrega el siguiente código.
@extends('layouts.app')@section('content')div @if (session('info')) div div div button type="button" data-dismiss="alert" aria-hidden="true"×/button {{ session('info') }} /div /div /div @elseif (session('error')) div div div button type="button" data-dismiss="alert" aria-hidden="true"×/button {{ session('error') }} /div /div /div @endif div div div divUpdate Profile/div div form method="POST" action="{{ route('profile.update', ['user' = $user]) }}" {{ csrf_field() }} {{ method_field('PUT') }} div label for="name"Name/label div input type="text" name="name" value="{{ $user-name }}" @if ($errors-has('name')) span strong{{ $errors-first('name') }}/strong /span @endif /div /div div label for="password"Password/label div input type="password" name="password" @if ($errors-has('password')) span strong{{ $errors-first('password') }}/strong /span @endif /div /div div label for="password-confirm"Confirm Password/label div input type="password" name="password_confirmation" /div /div div label for="current-password"Current Password/label div input type="password" name="current_password" @if ($errors-has('current_password')) span strong{{ $errors-first('current_password') }}/strong /span @endif /div /div div div button type="submit" Update /button /div /div /form /div /div /div /div/div@endsection
En nuestra página de “editar perfil”, buscamos un info
mensaje error
flash y se lo mostramos al usuario.
Tiene un campo name
, password
, password_confirmation
y current_password
.
La forma en que queremos que funcione es que cada vez que un usuario realiza un cambio, debe proporcionar el current_password
campo correcto para confirmar la actualización en la base de datos.
Los campos password
y password_confirmation
permiten al usuario cambiar su contraseña. Si ambos campos se dejan vacíos, se conservará la contraseña actual del usuario y no se realizarán cambios en la contraseña almacenada.
En nuestra opinión, los actores principales son los campos password
, password_confirmation
, y current_password
.
En cuanto al name
campo, sirve como ejemplo para ampliar y agregar más campos para su caso.
Paso 2: Creación de la solicitud de formulario
Ahora pasemos a la parte más crucial de este tutorial.
Ejecute el siguiente comando para crear una solicitud de formulario.
- php artisan make:request UpdateProfile
El comando anterior creará un archivo llamado app/Http/Requests/UpdateProfile.php
.
Todos los cambios de código en esta sección se realizarán en este archivo.
Lo primero que debemos hacer es crear un alias para la fachada Hash de Laravel antes de la declaración de la clase.
use IlluminateSupportFacadesHash;
A continuación, debemos regresar true
de nuestro authorize
método ya que no estamos realizando autorización en nuestra solicitud de formulario.
/** * Determine if the user is authorized to make this request. * * @return bool */public function authorize(){ return true;}
Nuestro método de reglas devolverá la matriz que describe las reglas de validación para esta solicitud.
/** * Get the validation rules that apply to the request. * * @return array */public function rules(){ return [ 'name' = 'required|string|max:255', 'password' = 'nullable|required_with:password_confirmation|string|confirmed', 'current_password' = 'required', ];}
Las name
reglas current_password
se explican por sí solas.
Las password
reglas establecen que la contraseña se confirmará mediante la confirmed
declaración.
También declara required_with:password_confirmation
lo que significa que si el usuario proporciona una confirmación de contraseña, también debe proporcionar una contraseña.
Estas reglas de validación se comprobarán automáticamente en cada solicitud una vez que las escribamos en nuestra acción del controlador (lo que haremos más adelante).
Lo último que debemos hacer es declarar un withValidator
método en nuestra solicitud al que se le pasa la instancia del validador completamente construida antes de que se active cualquiera de las reglas de validación.
/** * Configure the validator instance. * * @param IlluminateValidationValidator $validator * @return void */public function withValidator($validator){ // checks user current password // before making changes $validator-after(function ($validator) { if ( !Hash::check($this-current_password, $this-user()-password) ) { $validator-errors()-add('current_password', 'Your current password is incorrect.'); } }); return; }
Dentro de nuestro withValdator
método, hemos agregado un after
gancho, una función que se ejecutará después de que se hayan realizado todas las comprobaciones de validación.
En nuestro after
gancho, hemos comparado la contraseña proporcionada por el usuario con su contraseña establecida en la base de datos.
Nos da $this-current_password
el current_password
valor del campo de formulario, mientras que Laravel nos permite acceder al usuario actualmente autenticado mediante, $this-user()
por lo que $this-user()-password
nos da la contraseña en hash del usuario guardada en la base de datos.
Las dos contraseñas se comparan utilizando el método Hash
de la fachada check
.
Si la comprobación del hash falla, se agrega un error al validador con la clave current_password
que usa $validator-errors()-add('current_password', 'Your current password is incorrect.')
.
Aquí está nuestro UpdateProfile
formulario de solicitud completo.
?phpnamespace AppHttpRequests;use IlluminateFoundationHttpFormRequest;use IlluminateSupportFacadesHash;class UpdateProfile extends FormRequest{ /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'name' = 'required|string|max:255', 'password' = 'nullable|required_with:password_confirmation|string|confirmed', 'current_password' = 'required', ]; } /** * Configure the validator instance. * * @param IlluminateValidationValidator $validator * @return void */ public function withValidator($validator) { // checks user current password // before making changes $validator-after(function ($validator) { if ( !Hash::check($this-current_password, $this-user()-password) ) { $validator-errors()-add('current_password', 'Your current password is incorrect.'); } }); return; }}
Paso 3: Configuración del controlador
Para utilizar nuestra solicitud de formulario, necesitaremos escribirla en nuestra acción de controlador.
Ejecute el siguiente comando para generar el controlador de perfil.
- php artisan make:controller ProfileController
Abra el archivo app/Http/Controllers/ProfileController.php
y agregue las siguientes acciones del controlador.
public function __construct(){ $this-middleware('auth');}/** * Show the form for editing the specified resource. * * @param AppUser $user * @return IlluminateHttpResponse */public function edit(Request $request, User $user){ // user $viewData = [ 'user' = $user, ]; // render view with data return view('profile.edit', $viewData);}/** * Update the specified resource in storage. * * @param IlluminateHttpRequest $request * @param AppUser $user * @return IlluminateHttpResponse */public function update(UpdateProfile $request, User $user){ // form data $data = $request-all(); $user-update($data); return redirect(route('profile.edit', ['user' = $user])) -with('info', 'Your profile has been updated successfully.');}
El constructor del controlador de perfil configura el auth
middleware para asegurarse de que un usuario haya iniciado sesión antes de editar su perfil.
La edit
acción sirve a la vista con los datos de la vista mientras que la update
acción actualiza el perfil del usuario y redirecciona nuevamente a la página de edición del perfil con el mensaje flash correspondiente.
Tenga en cuenta la firma de la edit
acción donde hemos indicado el tipo de UpdateProfile
solicitud, que es todo lo que necesitamos hacer para activar las validaciones dentro de nuestra UpdateProfile
solicitud de formulario.
También necesitará crear un alias para la solicitud de formulario y el modelo de usuario antes de la declaración de la clase del controlador.
use AppHttpRequestsUpdateProfile;use AppUser;
Paso 4: Configuración de rutas protegidas y mutadores de datos
Abra el archivo app/routes/web.php
y agregue el siguiente código para vincular las acciones del controlador.
Route::get('/profile/{user}/edit', 'ProfileController@edit')-name('profile.edit');Route::put('/profile/{user}', 'ProfileController@update')-name('profile.update');
Según la regla de validación que agregamos anteriormente a nuestra solicitud de formulario, es posible que null
pase una contraseña.
Bajo ninguna circunstancia un usuario (o un desarrollador de aplicaciones) querría que su contraseña sea null
una cadena vacía.
Para asegurarnos de que la contraseña de un usuario se configure solo cuando éste la proporcione, utilizaremos los mutadores de Eloquent ORM.
Abra el archivo app/User.php
y agregue el siguiente código.
// Only accept a valid password and // hash a password before savingpublic function setPasswordAttribute($password){ if ( $password !== null $password !== "" ) { $this-attributes['password'] = bcrypt($password); }}
Los mutadores elocuentes deben seguir el esquema de nombres setcamel-cased-attribute-nameAttribute
.
Dado que estamos declarando un mutador para el password
atributo, hemos llamado al mutador setPasswordAttribute
.
A la función mutadora se le pasa el valor que se está estableciendo, que en nuestro mutador es la $password
variable.
En nuestro mutador, verificamos si la $password
variable no es nula o una cadena vacía y la establecemos en nuestro modelo usando $this-attributes['password']
.
Tenga en cuenta también que la contraseña se codifica antes de guardarla para que no tengamos que hacerlo en otra parte de nuestra aplicación.
Laravel predeterminado Auth/RegisterController
también Auth/ResetPasswordController
codifica la contraseña antes de guardarla en la base de datos, por lo que debemos actualizar el método create
y resetPassword
en los respectivos controladores después de declarar el mutador anterior.
Abra el archivo app/Http/Controllers/Auth/RegisterController.php
y agregue el siguiente código.
/** * Create a new user instance after a valid registration. * * @param array $data * @return AppUser */protected function create(array $data){ return User::create([ 'name' = $data['name'], 'email' = $data['email'], 'password' = $data['password'], ]);}
Abra el archivo app/Http/Controllers/Auth/ResetPasswordController.php
y agregue el siguiente código.
/** * Reset the given user's password. * * @param IlluminateContractsAuthCanResetPassword $user * @param string $password * @return void */protected function resetPassword($user, $password){ $user-password = $password; $user-setRememberToken(Str::random(60)); $user-save(); event(new PasswordReset($user)); $this-guard()-login($user);}
Para el ResetPasswordController
, también necesitará crear alias para las clases respectivas utilizadas antes de la declaración de clase.
use IlluminateSupportStr;use IlluminateAuthEventsPasswordReset;
Hemos terminado y nuestra verificación de contraseña funciona como se esperaba.
Conclusión
En esta guía, vimos cómo implementar un paso adicional de verificación de contraseña para confirmar que un usuario está autorizado a acceder a un área de administración. Vimos cómo crear y configurar solicitudes de formulario para implementar la validación de formulario dentro de una aplicación Laravel.
Para obtener más información sobre la validación y las solicitudes de formulario, puede consultar la documentación oficial de Laravel.
Deja una respuesta