如何使用Laravel表单请求实施密码验证

news/2024/7/5 6:53:49

介绍 (Introduction)

Laravel form requests are special classes that extend the functionality of regular request classes, enabling advanced validation features. Form requests also help to keep your controller actions a lot cleaner, because you can move all your validation logic to the form request class. Another benefit is that it allows you to filter requests before they reach your controller actions.

Laravel 表单请求是特殊类,可扩展常规请求类的功能,从而启用高级验证功能 。 表单请求还可以使您的控制器操作更加简洁,因为您可以将所有验证逻辑移至表单请求类。 另一个好处是,它允许您在请求到达控制器操作之前对其进行过滤。

In this guide, we’ll implement a password verification step to request that a user confirms their password before accessing an admin area. This practice works as a double check and provides your application an extra layer of security.

在本指南中,我们将实施密码验证步骤,以要求用户在访问管理区域之前确认密码。 这种做法可以作为双重检查,并为您的应用程序提供额外的安全性。

先决条件 (Prerequisites)

To follow up with this guide, you’ll need a working Laravel 5.6+ application with the built-in Laravel authentication set up. Please check the official documentation for details on how to set this up.

要继续遵循本指南,您将需要一个具有内置Laravel身份验证设置的可运行Laravel 5.6+应用程序。 请检查官方文档以获取有关设置方法的详细信息。

第1步-创建视图 (Step 1 — 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’ll 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

In our “edit profile” page, we check for an info and error flash message and display it to the user.

在“编辑个人资料”页面中,我们检查是否有infoerror提示信息,并将其显示给用户。

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字段,它是一个示例,可以根据您的情况进行扩展并添加更多字段。

第2步-创建表单请求 (Step 2 — 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

    php artisan make:request UpdateProfile

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 self-explanatory.

namecurrent_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’ll 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 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;
    }
}

步骤3 —设置控制器 (Step 3 — Setting Up the Controller)

To use our form request, we’ll need to type-hint it in our controller action.

要使用表单请求,我们需要在控制器操作中键入提示。

Execute the following command to generate the profile controller.

执行以下命令以生成概要文件控制器。

  • php artisan make:controller ProfileController

    php artisan make:controller ProfileController

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操作将更新用户配置文件,并使用相应的刷新消息重定向回编辑配置文件页面。

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;

步骤4 —设置受保护的路由和数据变量 (Step 4 — Setting up Protected Routes and Data Mutators)

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');

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 check if the $password variable is not null or an empty string and set it in 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在将密码持久保存到数据库之前,还会对密码进行哈希处理,因此,我们需要在声明上述变体之后在相应的控制器中更新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;

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.

当提供错误密码或不提供密码时,对应用程序进行测试运行会产生以下行为,如屏幕截图所示。

结论 (Conclusion)

In this guide, we saw how to implement an additional password verification step to assert that a user is authorized to access an admin area. We’ve seen how to create and set up form requests to implement form validation within a Laravel application.

在本指南中,我们看到了如何执行额外的密码验证步骤来断言用户已被授权访问管理区域。 我们已经看到了如何创建和设置表单请求以在Laravel应用程序中实现表单验证。

For more information about validation and form requests, you can check the official Laravel documentation.

有关验证和表单请求的更多信息,您可以查看Laravel官方文档 。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-implement-password-verification-using-laravel-form-request


http://www.niftyadmin.cn/n/3649146.html

相关文章

Dagger2的简单使用

解耦和方式 1、利用配置文件&#xff0c;使用反射获取到需要加载的对象。 2、设计模式&#xff1a;单例、工厂、观察者…… Dagger2简介 1、什么是Dagger2&#xff1f; Dagger是为Android和Java平台提供的在编译时进行依赖注入的框架。 编译时&#xff1a;编辑时生成代码&#…

[收藏]“白发”,已经成为IT人的特征之一

2004年中国IT渠道的“七种”颜色作者&#xff1a; 《计算机产品与流通》白发一次采访中&#xff0c;不经意间瞥到了被访者的鬓角&#xff0c;发现这位还不到40岁的总经理&#xff0c;居然已经是两鬓班白。更令人惊奇的是&#xff0c;坐在旁边的副总经理也已白发满头。自此&…

react hooks使用_使用React Hooks将React类组件转换为功能组件的五种方法

react hooks使用The latest alpha release of React introduced a new concept called Hooks. Hooks were introduced to React to solve common problems; however, they primarily serve as an alternative for classes. With Hooks, you can create functional components t…

Genymotion安卓模拟器常见问题汇总

Genymotion模拟器在安装好多由于电脑设备的关系可能出现兼容性、网络连接等问题&#xff0c;这里带来它们的解决方法。 1、关于兼容性的关键 下载完把这个zip文件&#xff08;点我下载&#xff09;直接拖到手机虚拟屏幕上就会提示安装&#xff0c;安装完了就会要求重启手机&…

Ubuntu 12.04下LAMP安装配置(转)

想要安装一台 Ubuntu 12.04版的Linux服务器&#xff0c;用这台服务器上的LAMP套件来运行我自己的个人网站。LAMP套件就是“LinuxApacheMysqlPHP这四款软件组成了一个可以使网站运行的套装工具软件。”通过安装尝试&#xff0c;我获得了一些成功的安装配置经验&#xff0c;通过本…

Retrofit的简单使用

一、Retorfit简介 Retorfit是一个功能强大的联网工具。可以看成是OKHttp数据解析&#xff08;json、xml等&#xff09;的组合。 说明文档&#xff1a;http://square.github.io/retrofit/ GitHub:https://github.com/square/retrofit 二、使用手册 1.引入配置 添加Retrofit依赖:…

如何为自定义Vue.js组件添加`v-model`支持

介绍 (Introduction) The v-model directive is one of the few directives that comes bundled with Vue.js. This directive allows for two-way data binding between our data and views. v-model指令是Vue.js附带的少数几个指令之一。 该指令允许在我们的数据和视图之间进…

mongodb启动失败[转]

现象&#xff1a; 查看日志的内容如下 Tue Jan 4 09:51:37 MongoDB starting : pid2794 port27017 dbpath/var/lib/mongodb 32-bit ** NOTE: when using MongoDB 32 bit, you are limited to about 2 gigabytes of data ** see http://blog.mongodb.org/post/137788967/…