使用Laravel表单请求进行密码验证

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.

我们检查infoerror Flash消息并将其显示给用户。

It has a name, password, password_confirmation, and current_password field.

它具有一个namepasswordpassword_confirmationcurrent_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.

passwordpassword_confirmation字段将允许用户更改其密码。 如果它们都保留为空,则将保留用户的当前密码,并且不会更改其存储的密码。

The major players in our view are the password, password_confirmation, and current_password fields.

我们认为主要的参与者是passwordpassword_confirmationcurrent_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

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.

namecurrent_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

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/RegisterControllerAuth/ResetPasswordController在将密码持久保存到数据库之前,还会对密码进行哈希处理,因此,我们需要在声明上述resetPassword器之后在相应的控制器中更新createresetPassword方法。

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

Password Required

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值