重置密码

Introduction

大多数 Web 应用程序都为用户提供了一种重置其忘记的密码的方法。 Laravel 不是强迫你为你创建的每个应用程序手动重新实现它,而是提供方便的服务来发送密码重置链接和安全重置密码。

Note
想要快速入门?安装 Laravel应用入门套件 在一个新的 Laravel 应用程序中。 Laravel 的初学者工具包将负责构建您的整个身份验证系统,包括重置忘记的密码。

模型准备

在使用 Laravel 的密码重置功能之前,你的应用程序的App\Models\User 模型必须使用Illuminate\Notifications\Notifiable 特征。通常,此特征已包含在默认值中App\Models\User 使用新的 Laravel 应用程序创建的模型。

接下来,验证您的App\Models\User 模型实现了Illuminate\Contracts\Auth\CanResetPassword 合同。这App\Models\User 框架中包含的模型已经实现了这个接口,并使用Illuminate\Auth\Passwords\CanResetPassword trait 包含实现接口所需的方法。

数据库准备

必须创建一个表来存储应用程序的密码重置令牌。此表的迁移包含在默认的 Laravel 应用程序中,因此您只需要迁移数据库即可创建此表:

php artisan migrate

配置可信主机

默认情况下,无论 HTTP 请求的内容如何,​​Laravel 都会响应它收到的所有请求Host 标头。除此之外Host 在 Web 请求期间为您的应用程序生成绝对 URL 时将使用标头的值。

通常,您应该将 Web 服务器(例如 Nginx 或 Apache)配置为仅向您的应用程序发送与给定主机名匹配的请求。然而,如果你没有能力直接定制你的 web 服务器并且需要指示 Laravel 只响应特定的主机名,你可以通过启用App\Http\Middleware\TrustHosts 您的应用程序的中间件。当您的应用程序提供密码重置功能时,这一点尤为重要。

要了解有关此中间件的更多信息,请参阅TrustHosts 中间件文档.

Routing

为了正确实现允许用户重置密码的支持,我们需要定义几个路由。首先,我们需要一对路由来处理允许用户通过他们的电子邮件地址请求密码重置链接。其次,一旦用户访问通过电子邮件发送给他们的密码重置链接并完成密码重置表单,我们将需要一对路由来处理实际重置密码。

请求密码重置链接

密码重置链接申请表

首先,我们将定义请求密码重置链接所需的路由。首先,我们将定义一个路由,该路由返回一个带有密码重置链接请求表单的视图:

Route::get('/forgot-password', function () {
    return view('auth.forgot-password');
})->middleware('guest')->name('password.request');

该路由返回的视图应该有一个包含email 字段,这将允许用户请求给定电子邮件地址的密码重置链接。

处理表单提交

接下来,我们将定义一个路由来处理来自“忘记密码”视图的表单提交请求。该路由将负责验证电子邮件地址并将密码重置请求发送给相应的用户:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

Route::post('/forgot-password', function (Request $request) {
    $request->validate(['email' => 'required|email']);

    $status = Password::sendResetLink(
        $request->only('email')
    );

    return $status === Password::RESET_LINK_SENT
                ? back()->with(['status' => __($status)])
                : back()->withErrors(['email' => __($status)]);
})->middleware('guest')->name('password.email');

在继续之前,让我们更详细地研究这条路线。首先,请求的email 属性已验证。接下来,我们将使用 Laravel 内置的“密码代理”(通过Password facade) 向用户发送密码重置链接。密码代理将负责通过给定字段(在本例中为电子邮件地址)检索用户,并通过 Laravel 的内置向用户发送密码重置链接通知系统.

sendResetLink 方法返回一个“状态”段。这个状态可以使用 Laravel 的翻译localization 助手,以便向用户显示有关其请求状态的用户友好消息。密码重置状态的转换由您的应用程序决定lang/{lang}/passwords.php语言文件。 status slug 的每个可能值的条目位于passwords 语言文件。

Note 默认情况下,Laravel 应用程序框架不包括lang 目录。如果你想自定义 Laravel 的语言文件,你可以通过lang:publish 工匠命令。

你可能想知道 Laravel 是如何知道在调用Password 门面的sendResetLink 方法。 Laravel 密码代理利用您的身份验证系统的“用户提供程序”来检索数据库记录。密码代理使用的用户提供程序在passwords 你的配置数组config/auth.php 配置文件。要了解有关编写自定义用户提供程序的更多信息,请参阅认证文件.

Note
手动实现密码重置时,您需要自己定义视图和路由的内容。如果您想要包含所有必要的身份验证和验证逻辑的脚手架,请查看Laravel 应用程序入门套件.

重置密码

密码重置表

接下来,我们将定义在用户单击通过电子邮件发送给他们的密码重置链接并提供新密码后实际重置密码所需的路由。首先,让我们定义将显示用户单击重置密码链接时显示的重置密码表单的路由。这条路线将收到token 我们稍后将用于验证密码重置请求的参数:

Route::get('/reset-password/{token}', function (string $token) {
    return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');

此路由返回的视图应显示一个包含email 领域,一个password 领域,一个password_confirmation 领域,和一个隐藏的token 字段,其中应包含秘密的值$token 通过我们的路线收到。

处理表单提交

当然,我们需要定义一个路由来实际处理密码重置表单提交。该路由将负责验证传入请求并更新数据库中的用户密码:

use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;

Route::post('/reset-password', function (Request $request) {
    $request->validate([
        'token' => 'required',
        'email' => 'required|email',
        'password' => 'required|min:8|confirmed',
    ]);

    $status = Password::reset(
        $request->only('email', 'password', 'password_confirmation', 'token'),
        function (User $user, string $password) {
            $user->forceFill([
                'password' => Hash::make($password)
            ])->setRememberToken(Str::random(60));

            $user->save();

            event(new PasswordReset($user));
        }
    );

    return $status === Password::PASSWORD_RESET
                ? redirect()->route('login')->with('status', __($status))
                : back()->withErrors(['email' => [__($status)]]);
})->middleware('guest')->name('password.update');

在继续之前,让我们更详细地研究这条路线。首先,请求的token,email, 和password 属性得到验证。接下来,我们将使用 Laravel 内置的“密码代理”(通过Password facade) 来验证密码重置请求凭据。

如果提供给密码代理的令牌、电子邮件地址和密码有效,则闭包传递给reset 方法将被调用。在这个接收用户实例和提供给密码重置表单的纯文本密码的闭包中,我们可以更新数据库中的用户密码。

reset 方法返回一个“状态”段。这个状态可以使用 Laravel 的翻译localization 助手,以便向用户显示有关其请求状态的用户友好消息。密码重置状态的转换由您的应用程序决定lang/{lang}/passwords.php 语言文件。 status slug 的每个可能值的条目位于passwords 语言文件。如果您的申请不包含lang 目录,您可以使用lang:publish 工匠命令。

在继续之前,你可能想知道 Laravel 是如何知道在调用Password 门面的reset 方法。 Laravel 密码代理利用您的身份验证系统的“用户提供程序”来检索数据库记录。密码代理使用的用户提供程序在passwords 你的配置数组config/auth.php 配置文件。要了解有关编写自定义用户提供程序的更多信息,请参阅认证文件.

删除过期的令牌

已过期的密码重置令牌仍将存在于您的数据库中。但是,您可以使用auth:clear-resets 工匠命令:

php artisan auth:clear-resets

如果您想自动执行此过程,请考虑将命令添加到您的应用程序的scheduler:

$schedule->command('auth:clear-resets')->everyFifteenMinutes();

Customization

重置链接自定义

您可以使用自定义密码重置链接 URLcreateUrlUsing 提供的方法ResetPassword 通知类。此方法接受一个闭包,该闭包接收接收通知的用户实例以及密码重置链接令牌。通常,您应该从您的App\Providers\AuthServiceProvider服务供应商boot 方法:

use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;

/**
 * Register any authentication / authorization services.
 */
public function boot(): void
{
    ResetPassword::createUrlUsing(function (User $user, string $token) {
        return 'https://example.com/reset-password?token='.$token;
    });
}

重置电子邮件自定义

您可以轻松修改用于向用户发送密码重置链接的通知类。首先,覆盖sendPasswordResetNotification 你的方法App\Models\User 模型。在此方法中,您可以使用任何方式发送通知通知类 你自己的创造。密码重置$token 是该方法收到的第一个参数。你可以用这个$token 构建您选择的密码重置 URL 并将您的通知发送给用户:

use App\Notifications\ResetPasswordNotification;

/**
 * Send a password reset notification to the user.
 *
 * @param  string  $token
 */
public function sendPasswordResetNotification($token): void
{
    $url = 'https://example.com/reset-password?token='.$token;

    $this->notify(new ResetPasswordNotification($url));
}
豫ICP备18041297号-2