重置密码
重置密码
介绍
大多数Web应用程序都会为用户提供重置密码的功能。 Laravel 已经提供了便捷的服务来发送密码重置链接和安全重置密码,而不需要您为每个应用程序重新实现此功能。
技巧:想快速上手? 在新的 Laravel 应用程序中安装 Laravel 入门套件。 Laravel 入门套件会为您搭建完整的身份验证系统, 包括重置密码功能。
模型准备
在使用 Laravel 的重置密码功能之前,确认 App\Models\User
模型已经使用了 Illuminate\Notifications\Notifiable
性状。 通常,在新创建的 Laravel 应用程序的 App\Models\User
模型中默认引入了该性状。
接下来,验证 App\Models\User
模型是否继承了 Illuminate\Contracts\Auth\CanResetPassword
接口。
框架中包含的 App\Models\User
模型默认继承了此接口,并使用 Illuminate\Auth\Passwords\CanResetPassword
性状来实现了接口中的方法。
数据库准备
必须创建一个表来存储应用程序的重置密码的令牌。 Laravel 应用程序中,默认包含了此表的迁移,因此,您只需执行以下命令即可创建此表:
php artisan migrate
路由
为了正确实现允许用户重置密码的支持,我们需要定义几个路由。首先,我们需要一对路由来处理,允许用户通过电子邮件地址请求密码重置链接。第二,一旦用户访问通过电子邮件发送给他们的密码重置链接并完成密码重置表单,我们将需要一对路由来处理实际重置密码请求。
请求密码重置链接
密码重置链接请求表单
首先,我们将定义请求密码重置链接所需的路由。首先,我们将定义一个路由,该路由使用密码重置链接请求表单返回一个视图:
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
门面向用户发送一个密码重置链接。密码代理将负责按给定字段(在本例中是电子邮件地址)检索用户,并通过Laravel的内置消息通知系统 向用户发送密码重置链接。
sendResetLink
方法返回一个状态标识。可以使用Laravel的 本地化 助手来转换此状态,以便向用户显示有关请求状态的用户友好提示。密码重置状态的转换由应用程序的resources/lang/{lang}/passwords.php
语言文件确定。状态slug的每个可能值的条目位于 passwords
语言文件中。
您可能想知道,在调用 Password
门面的 sendResetLink
方法时,Laravel 怎么知道如何从应用程序数据库中检索用户记录。Laravel密码代理利用身份验证系统的“用户提供者”来检索数据库记录。密码代理使用的用户提供程序是在 config/auth.php
配置文件的 passwords
配置数组中配置的。要了解有关编写自定义用户提供程序的更多信息,请参阅身份验证文档
技巧:当手动实现密码重置时,您需要自己定义视图和路由的内容。如果您想要包含所有必要的身份验证和验证逻辑的脚手架,请查看Laravel application starter kits.
重置密码
重置密码表单
接下来,我们将定义用户点击重置密码邮件中的链接,进行重置密码所需要的一些路由。第一步,先定义一个获取重置密码表单的路由。这个路由需要一个 token
来验证请求:
Route::get('/reset-password/{token}', function ($token) {
return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');
通过路由返回的视图应该显示一个含有 email
字段, password
字段, password_confirmation
字段和一个隐藏的值通过路由参数获取的 token
字段。
处理表单提交的数据
当然,我们需要定义一个路由来接受表单提交的数据。这个路由会检查传过来的参数并更新数据库中用户的密码:
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, $password) use ($request) {
$user->forceFill([
'password' => Hash::make($password)
])->save();
$user->setRememberToken(Str::random(60));
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 broker”(通过 Password
门面)来验证密码重置。
如果提供给密码代理的令牌、电子邮件地址和密码有效,则将调用传递给 reset
方法的闭包。 在这个接收用户实例和纯文本密码的闭包中,我们可以更新数据库中用户的密码。
reset
方法返回一个 “状态” 标识。 此状态可以使用 Laravel 的 localization 助手进行翻译,以便向用户显示有关其请求状态的友好提示。 密码重置状态的翻译由您的应用程序的resources/lang/{lang}/passwords.php
语言文件决定。 状态标识的每个可能值的条目位于 passwords
语言文件中。
在继续之前,您可能想知道 Laravel 如何在调用 Password
门面的 reset
方法时知道如何从应用程序的数据库中检索用户记录。 Laravel 密码代理利用您的身份验证系统的 “user providers” 来检索数据库记录。 密码代理使用的用户提供程序在你的 config/auth.php
配置文件的 passwords
配置数组中配置。 要了解有关编写自定义用户提供程序的更多信息,请参阅 身份验证文档
自定义
重置链接自定义
您可以使用 ResetPassword
通知类提供的 createUrlUsing
方法自定义密码重置链接 URL。 此方法接受一个闭包,该闭包接收正在接收通知的用户实例以及密码重置链接令牌。 通常,您应该从 App\Providers\AuthServiceProvider
服务提供者的 boot
方法中调用此方法:
use Illuminate\Auth\Notifications\ResetPassword;
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
ResetPassword::createUrlUsing(function ($user, string $token) {
return 'https://example.com/reset-password?token='.$token;
});
}
重置邮件自定义
您可以轻松修改用于向用户发送密码重置链接的通知类。 首先,覆盖您的 App\Models\User
模型上的 sendPasswordResetNotification
方法。 在此方法中,您可以使用您自己创建的任何 通知类 发送通知。 密码重置 $token
是该方法收到的第一个参数。 你可以使用这个 $token
来构建你选择的密码重置 URL 并将你的通知发送给用户:
use App\Notifications\ResetPasswordNotification;
/**
* 发送密码重置通知给用户
*
* @param string $token
* @return void
*/
public function sendPasswordResetNotification($token)
{
$url = 'https://example.com/reset-password?token='.$token;
$this->notify(new ResetPasswordNotification($url));
}