You might have observed in a lot of applications, some parts require you to re-enter your password in order to proceed further or perform a desired action.
您可能已经在很多应用程序中观察到过,某些部分要求您重新输入密码才能继续操作或执行所需的操作。
An example of it is Twitter's edit password section. In order to set a new password, you must also provide your current password.
Twitter的“编辑密码”部分就是一个例子。 为了设置新密码,您还必须提供当前密码。
Such a strategy works well as a double check and provides your application an extra layer of security.
这样的策略可以很好地进行仔细检查,并为您的应用程序提供额外的安全性。
In this quick tip, I am going to show you how to add such a functionality to your Laravel application using Laravel's form request.
在这个快速提示中,我将向您展示如何使用Laravel的form request将这样的功能添加到您的Laravel应用程序中。
申请表格入门 ( A Primer on Form Request )
So, what is a form request?
那么,什么是表格请求?
Let us start by having a look at Laravel's official documentation.
让我们开始看看Laravel的官方文档 。
Form requests are custom request classes that contain validation logic.
表单请求是包含验证逻辑的自定义请求类。
As someone who has deep-dived into form requests, I would say they are not limited to performing validation.
作为深入研究表单请求的人,我想说他们不仅限于执行验证。
For a start, you can also authorize a user against an action using a form request.
首先,您还可以使用表单请求授权用户执行某项操作。
Form requests also help to keep your controller actions a lot cleaner.
表单请求还有助于使您的控制器操作更加整洁。
Instead of dumping all the validation and conditional statements inside a controller action, you should opt to use a form request.
您应该选择使用表单请求,而不是将所有验证和条件语句转储到控制器操作中。
And finally, form requests in a way, serve as a component to filter requests before they reach your controller actions.
最后,表单请求在某种程度上可以用作在请求到达您的控制器操作之前过滤请求的组件。
For this quick tip, I am going to assume you have the built-in Laravel authentication set up and working as it is beyond the scope of this tutorial to show how to set up Laravel authentication.
对于此快速提示,我将假定您已设置并内置了Laravel身份验证,并且它已经超出了本教程的范围,无法显示如何设置Laravel身份验证 。
创建视图 ( Creating the View )
We are going to start by setting up a user's edit profile page.
我们将从设置用户的编辑个人资料页面开始。
At the time of writing this tutorial, artisan
command utility does not generate views so we will need to create the view manually.
在撰写本教程时, artisan
命令实用程序不会生成视图,因此我们将需要手动创建视图。
Create the file resources/views/profile/edit.blade.php
and add the following code.
创建文件resources/views/profile/edit.blade.php
并添加以下代码。
@extends('layouts.app')
@section('content')<div class="container">
@if (session('info'))
<div class="row">
<div class="col-md-12">
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ session('info') }}
</div>
</div>
</div>
@elseif (session('error'))
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ session('error') }}
</div>
</div>
</div>
@endif
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Update Profile</div>
<div class="panel-body">
<form class="form-horizontal" method="POST" action="{{ route('profile.update', ['user' => $user]) }}">
{{ csrf_field() }}
{{ method_field('PUT') }}
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
<label for="name" class="col-md-4 control-label">Name</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control" name="name" value="{{ $user->name }}">
@if ($errors->has('name'))
<span class="help-block">
<strong>{{ $errors->first('name') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation">
</div>
</div>
<div class="form-group{{ $errors->has('current_password') ? ' has-error' : '' }}">
<label for="current-password" class="col-md-4 control-label">Current Password</label>
<div class="col-md-6">
<input id="current-password" type="password" class="form-control" name="current_password">
@if ($errors->has('current_password'))
<span class="help-block">
<strong>{{ $errors->first('current_password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Update
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Our edit profile page is pretty simple.
我们的编辑个人资料页面非常简单。
We check for an info
and error
flash message and display it to the user.
我们检查info
和error
Flash消息并将其显示给用户。
It has a name
, password
, password_confirmation
, and current_password
field.
它具有一个name
, password
, password_confirmation
和current_password
字段。
The way we want it to work is whenever a user makes a change, they have to provide the correct current_password
field to commit the update to the database.
我们希望它的工作方式是每当用户进行更改时,他们都必须提供正确的current_password
字段才能将更新提交到数据库。
The password
and password_confirmation
fields will allow the user to change their password. If they are both left empty, the user's current password will be retained and no changes will be made to their stored password.
password
和password_confirmation
字段将允许用户更改其密码。 如果它们都保留为空,则将保留用户的当前密码,并且不会更改其存储的密码。
The major players in our view are the password
, password_confirmation
, and current_password
fields.
我们认为主要的参与者是password
, password_confirmation
和current_password
字段。
As for the name
field, it serves as an example to expand upon and add more fields for your case.
至于name
字段,它是一个示例,可以根据您的情况扩展并添加更多字段。
创建表单请求 ( Creating the Form Request )
Now onto the most crucial part of this tutorial.
现在进入本教程最关键的部分。
Execute the following command to create a form request.
执行以下命令以创建表单请求。
$ php artisan make:request UpdateProfile
![Artisan Make Request](https://i-blog.csdnimg.cn/blog_migrate/d9660d411e8ab82e47d698a7006c2de1.png)
The above command will create a file named app/Http/Requests/UpdateProfile.php
.
上面的命令将创建一个名为app/Http/Requests/UpdateProfile.php
。
All code changes in this section will be made to this file.
本部分中的所有代码更改都将对此文件进行。
The first thing we need to do is alias Laravel's Hash facade before the class declaration.
我们需要做的第一件事是在类声明之前使用别名Laravel的Hash门面 。
use Illuminate\Support\Facades\Hash;
Next, we need to return true
from our authorize
method since we are not performing authorization in our form request.
接下来,由于我们不在表单请求中执行授权,因此我们需要从authorize
方法返回true
。
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
Our rules method will return the array outlining the validation rules for this request.
我们的rules方法将返回概述此请求验证规则的数组。
/**
* 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',
];
}
The name
and current_password
rules are pretty self-explanatory.
name
和current_password
规则很current_password
解释。
The password
rules states that the password will be confirmed using the confirmed
declaration.
password
规则指出,将使用已confirmed
声明来确认密码。
It also declares required_with:password_confirmation
which means if the user provides a password confirmation, they should also provide a password.
它还声明了required_with:password_confirmation
,这意味着如果用户提供密码确认,则他们还应该提供密码。
These validation rules will be checked automatically upon every request once we type-hint it in our controller action(which we will do later).
一旦我们在控制器操作中键入提示,这些验证规则将在每次请求时自动检查(稍后我们将做)。
The last thing we need to do is declare a withValidator
method on our request which is passed the fully constructed validator instance before any of the validation rules fire.
我们需要做的最后一件事是在请求中声明一个withValidator
方法,该方法将在触发任何验证规则之前传递给完全构造的验证器实例。
/**
* Configure the validator instance.
*
* @param \Illuminate\Validation\Validator $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;
}
Inside our withValdator
method, we have added an after
hook, a function which will be executed after all the validation checks have been made.
在withValdator
方法内部,我们添加了一个after
钩子,该函数将在完成所有验证检查后执行。
In our after
hook, we have simply compared the user's provided password with their password set in the database.
在after
钩子中,我们仅将用户提供的密码与他们在数据库中设置的密码进行了比较。
The $this->current_password
gives us the current_password
form field value whereas Laravel allows us to access the currently authenticated user using $this->user()
so $this->user()->password
gives us the user's hashed password saved in the database.
$this->current_password
为我们提供了current_password
表单字段值,而Laravel允许我们使用$this->user()
访问当前经过身份验证的用户,因此$this->user()->password
为我们提供了用户的哈希密码保存在数据库。
The two passwords are compared using the Hash
facade's check
method.
使用Hash
外观的check
方法比较这两个密码。
If the hash check fails, an error is added to the validator with the key current_password
using $validator->errors()->add('current_password', 'Your current password is incorrect.')
.
如果哈希检查失败,则使用$validator->errors()->add('current_password', 'Your current password is incorrect.')
使用密钥current_password
将错误添加到验证器。
Here is our complete UpdateProfile
form request.
这是我们完整的UpdateProfile
表单请求。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Hash;
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 \Illuminate\Validation\Validator $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;
}
}
控制器动作 ( The Controller Action )
To use our form request, we will need to type-hint it in our controller action.
要使用表单请求,我们将需要在控制器操作中键入提示。
Execute the following command to generate the profile controller.
执行以下命令以生成概要文件控制器。
$ php artisan make:controller ProfileController
![Artisan Make Controller](https://i-blog.csdnimg.cn/blog_migrate/5f4f9beb787483ae27bdd0db8eea2801.png)
Open the file app/Http/Controllers/ProfileController.php
and add the following controller actions.
打开文件app/Http/Controllers/ProfileController.php
并添加以下控制器操作。
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the form for editing the specified resource.
*
* @param \App\User $user
* @return \Illuminate\Http\Response
*/
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 \Illuminate\Http\Request $request
* @param \App\User $user
* @return \Illuminate\Http\Response
*/
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.');
}
The profile controller's constructor sets the auth
middleware to make sure a user is logged in before editing his/her profile.
概要文件控制器的构造函数设置auth
中间件,以确保用户在编辑其概要文件之前已登录。
The edit
action serves the view with the view data whereas the update
action updates the user profile and redirects back to the edit profile page with the corresponding flash message.
edit
操作将视图数据提供给视图,而update
操作将更新用户配置文件并使用相应的Flash消息重定向回编辑配置文件页面。
Notice the signature of the edit
action where we have type-hinted the UpdateProfile
request which is all we need to do to fire the validations inside our UpdateProfile
form request.
注意,在我们键入提示UpdateProfile
请求的位置,执行了edit
动作的签名,这是我们在UpdateProfile
表单请求中触发验证所需要做的全部工作。
You will also need to alias the form request and the user model before the controller class declaration.
您还需要在控制器类声明之前为表单请求和用户模型添加别名。
use App\Http\Requests\UpdateProfile;
use App\User;
设置路线 ( Setting up the Route )
Open the file app/routes/web.php
and add the following code to tie in the controller actions.
打开文件app/routes/web.php
并添加以下代码以绑定控制器操作。
Route::get('/profile/{user}/edit', 'ProfileController@edit')->name('profile.edit');
Route::put('/profile/{user}', 'ProfileController@update')->name('profile.update');
添加最终修饰 ( Adding Final Touches )
Based on the validation rule we added earlier to our form request, it is possible for a null
password to pass through.
根据我们之前在表单请求中添加的验证规则,可能会传递null
密码。
Under no circumstances would a user(or an application developer) want their password to be set to null
or an empty string.
用户(或应用程序开发人员)在任何情况下都不会希望将其密码设置为null
或空字符串。
To make sure a user password is set only when they provide one, we are going to use Eloquent ORM's mutators.
为了确保仅在提供用户密码时才设置用户密码,我们将使用Eloquent ORM的mutators 。
Open the file app/User.php
and add the following code.
打开文件app/User.php
并添加以下代码。
// Only accept a valid password and
// hash a password before saving
public function setPasswordAttribute($password)
{
if ( $password !== null & $password !== "" )
{
$this->attributes['password'] = bcrypt($password);
}
}
Eloquent mutators have to follow the naming scheme set<camel-cased-attribute-name>Attribute
.
雄辩的更改者必须遵循命名方案set<camel-cased-attribute-name>Attribute
。
Since we are declaring a mutator for the password
attribute hence we have named the mutator setPasswordAttribute
.
由于我们声明了password
属性的变量,因此我们将变量命名为setPasswordAttribute
。
The mutator function is passed the value being set which in our mutator is the $password
variable.
传递mutator函数所设置的值,该变量在我们的mutator中是$password
变量。
In our mutator, we simply check the $password
variable is not null and an empty string and set it on our model using $this->attributes['password']
.
在我们的增变器中,我们只需检查$password
变量是否不为null以及是否为空字符串,然后使用$this->attributes['password']
在模型上进行设置。
Also note the password is hashed before saving so we do not have to do it elsewhere in our application.
还要注意,密码在保存之前已经过哈希处理,因此我们不必在应用程序的其他位置进行密码处理。
The default Laravel Auth/RegisterController
and Auth/ResetPasswordController
also hash the password before persisting it to the database so we need to update the create
and resetPassword
method in the respective controllers after declaring the above mutator.
默认的Laravel Auth/RegisterController
和Auth/ResetPasswordController
在将密码持久保存到数据库之前,还会对密码进行哈希处理,因此,我们需要在声明上述resetPassword
器之后在相应的控制器中更新create
和resetPassword
方法。
Open the file app/Http/Controllers/Auth/RegisterController.php
and add the following code.
打开文件app/Http/Controllers/Auth/RegisterController.php
并添加以下代码。
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => $data['password'],
]);
}
Open the file app/Http/Controllers/Auth/ResetPasswordController.php
and add the following code.
打开文件app/Http/Controllers/Auth/ResetPasswordController.php
并添加以下代码。
/**
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $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);
}
For the ResetPasswordController
, you will also need to alias the respective classes used before the class declaration.
对于ResetPasswordController
,您还需要为类声明之前使用的相应类添加别名。
use Illuminate\Support\Str;
use Illuminate\Auth\Events\PasswordReset;
幕布 ( Curtains )
We are all done and our password verification works as expected.
我们已经完成了所有工作,并且密码验证按预期进行了。
A test run of the application when providing an incorrect password or none yields the following behaviour demonstrated by the screenshots.
当提供错误的密码或不提供密码时,对应用程序进行测试运行会产生以下行为,如屏幕截图所示。
![Incorrect Password](https://i-blog.csdnimg.cn/blog_migrate/459163b298bfad42e566f1d4140c76d6.png)
![Password Required](https://i-blog.csdnimg.cn/blog_migrate/912a02bd6a45f09c34902580fdb147e2.png)
Is there a better way to accomplish this neat check in Laravel? I would love to hear about it in your comments.
在Laravel中是否有更好的方法来完成此整洁检查? 我很想在您的评论中听到它。
I hope you found this tutorial interesting and knowledgeable. Until my next piece, happy coding!
我希望您发现本教程有趣且知识丰富。 直到我的下一篇文章,祝您编程愉快!
翻译自: https://scotch.io/tutorials/password-verification-using-laravel-form-request