# Laravel Fortify
- [介绍](#introduction)
- [Fortify是什么?](#what-is-fortify)
- [何时使用Fortify?](#when-should-i-use-fortify)
- [安装](#installation)
- [服务提供者](#the-fortify-service-provider)
- [包含功能](#fortify-features)
- [禁用视图](#disabling-views)
- [认证](#authentication)
- [自定义认证](#customizing-user-authentication)
- [双重认证](#two-factor-authentication)
- [启用双重认证](#enabling-two-factor-authentication)
- [使用双重认证](#authenticating-with-two-factor-authentication)
- [禁用双重认证](#disabling-two-factor-authentication)
- [注册](#registration)
- [自定义注册](#customizing-registration)
- [重置密码](#password-reset)
- [请求重置密码链接](#requesting-a-password-reset-link)
- [重置密码](#resetting-the-password)
- [自定重置密码](#customizing-password-resets)
- [邮件认证](#email-verification)
- [保护路由](#protecting-routes)
- [确认密码](#password-confirmation)
## 介绍
Lravel Fortify是一个与前端无关的身份认证后端实现。Fortify注册了所有实现Laravel身份验证功能所需的路由和控制器,包括登录,注册,重置密码,邮件认证等。安装Fortify之后,你可以运行Artisan命令 `route:list` 来查看Fortify已注册的路由。
由于Fortify不提供其自己的用户界面,因此应与你自己的用户界面配对,该用户界面向其注册的路由发出请求。在本文档的其余部分中,我们将进一步讨论如何向这些路由发出请求。
> 技巧:请记住,Fortify是一个软件包,旨在使你能够快速开始实施Laravel的身份验证功能。**你不必非要使用它不可。** 你始终可以按照以下说明中提供的文档,自由地与Laravel的身份认证服务进行交互,[用户认证](/docs/laravel/8.x/authentication), [重置密码](/docs/laravel/8.x/passwords) 和 [邮箱认证](/docs/laravel/8.x/verification) 文档。
### Fortify是什么?
如上所述,Laravel Fortify 是一个与前端无关的身份认证后端实现,Fortify 注册了所有实现 Laravel 身份验证功能所需的路由和控制器,包括登录,注册,重置密码,邮件认证等。
**你不必使用Fortify,也可以使用Laravel的身份认证功能。** 你始终可以按照以下说明中提供的文档,自由地与 Laravel 的身份认证服务进行交互,[用户认证](/docs/laravel/8.x/authentication),[重置密码](/docs/laravel/8.x/passwords) 和 [邮箱认证](/docs/laravel/8.x/verification) 文档。
如果你是一名新手,在使用Laravel Fortify 之前不妨尝试使用[Laravel Breeze](/docs/laravel/8.x/starter-kits)应用入门套件。Laravel Breeze为你的应用提供身份认证支架,其中包括使用 [Tailwind CSS](https://tailwindcss.com)。与Fortify不同,Breeze将其路由和控制器直接发布到你的应用程序中。这使你可以学习并熟悉Laravel的身份认证功能,然后再允许Laravel Fortify为您实现这些功能。
Laravel Fortify本质上是采用了Laravel Breeze的路由和控制器,且提供了不包含用户界面的扩展。这样,你可以快速搭建应用程序身份认证层的后端实现,而不必依赖于任何特定的前端意见。
### 何时使用Fortify?
你可能想知道何时使用Laravel Fortify。 首先, 如果你正在使用Laravel的 [应用入门套件](/docs/laravel/8.x/starter-kits), 你不需要安装Laravel Fortify,因为它已经提供了完整的身份认证实现。
如果你不使用应用入门套件,并且你的应用需要身份认证功能,则有两个选择:手动实现应用的身份认证功能或使用由Laravel Fortify提供这些功能的后端实现。
如果你选择安装Fortify,你的用户界面将向Fortify的身份验证路由发出请求,本文档中对此进行了详细介绍,以便对用户进行身份认证和注册。
如果你选择手动与 Laravel 的身份认证服务进行交互而不是使用 Fortify,可以按照 [身份认证](/docs/laravel/8.x/authentication), [重置密码](/docs/laravel/8.x/passwords) 和 [邮箱认证](/docs/laravel/8.x/verification) 文档。
#### Laravel Fortify & Laravel Sanctum
一些开发人员对 [Laravel Sanctum](/docs/laravel/8.x/sanctum) 和 Laravel Fortify两者之间的区别感到困惑。由于这两个软件包解决了两个不同但相关的问题,因此Laravel Fortify 和 Laravel Sanctum 并非互斥或竞争的软件包。
Laravel Sanctum 只关心管理 API 令牌和使用会话 cookie 或令牌来认证现有用户。 Sanctum 不提供任何处理用户注册,重置密码等相关的路由。
如果你尝试为提供 API 或用作单页应用的后端的应用手动构建身份认证层,那么完全有可能同时使用 Laravel Fortify(用于用户注册,重置密码等)和 Laravel Sanctum(API 令牌管理,会话身份认证)。
## 安装
首先,使用 Composer 软件包管理器安装 Fortify:
```nothing
composer require laravel/fortify
```
下一步,使用 `vendor:publish` 命令来发布 Fortify 的资源:
```bash
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
```
该命令会将 Fortify 的行为类发布到您的 `app/Actions` 目录,如果该目录不存在,则会创建该目录。此外,还将发布 Fortify 的配置和迁移文件。
下一步,你应该迁移数据库:
```bash
php artisan migrate
```
### Fortify 服务提供商
上面讨论的 `vendor:publish` 命令还将发布 `App\Providers\FortifyServiceProvider` 类。你应该确保该类已在应用程序的 `config/app.php` 配置文件的 `providers` 数组中注册。
Fortify 服务提供商注册了 Fortify 所发布的行为类,并指导 Fortify 在执行各自的任务时使用它们。
### Fortify 包含的功能
`fortify` 配置文件包含一个 `features` 配置数组。 该数组默路定义了 Fortify 的路由和功能。如果你不打算将 Fortify 与 [Laravel Jetstream](https://jetstream.laravel.com) 配合使用,我们建议你仅启用以下功能,这是大多数 Laravel 应用提供的基本身份认证功能:
```php
'features' => [
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
],
```
### 禁用视图
默认情况下,Fortify 定义用于返回视图的路由,例如登录或注册。但是,如果要构建 JavaScript 驱动的单页应用,那么可能不需要这些路由。因此,你可以通过将`config/fortify.php` 配置文件中的 `views` 配置值设为 `false` 来禁用这些路由:
```php
'views' => false,
```
#### 禁用视图 & 重置密码
如果你选择禁用 Fortify 的视图,并且将为你的应用实现重置密码功能,这时你仍然需要定义一个名为 ` password.reset` 的路由,该路由负责显示应用的「重置密码」视图。这是必要的,因为 Laravel 的 `Illuminate\Auth\Notifications\ResetPassword` 通知将通过名为 `password.reset` 的路由生成重置密码 URL。
## 身份认证
首先,我们需要指导 Fortify 如何返回「登录」视图。记住,Fortify 是一个无头认证扩展。
如果你想要一个已经为你完成的 Laravel 身份认证功能的前端实现, 你应该使用 [应用入门套件](/docs/laravel/8.x/starter-kits).
所有的身份认证视图逻辑,都可以使用 `Laravel\Fortify\Fortify` 类提供的方法来自定义。通常,你应该从应用的 `App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用此方法。Fortify 将负责定义返回此视图的 `/login` 路由:
use Laravel\Fortify\Fortify;
/**
* 引导任何应用服务。
*
* @return void
*/
public function boot()
{
Fortify::loginView(fn () => view('auth.login'));
// ...
}
你的登录模板应包括一个向 `/login` 发出POST请求的表单。`/login` 表单需要一个电子邮件地址、用户名和一个 `password`。电子邮件、用户名字段与`config/fortify.php` 配置文件中的 `username` 值相匹配。另外,可以提供布尔值 `remember` 字段来指导用户想要使用 Laravel 提供的「记住我」功能。
如果登录尝试成功,Fortify 会将您重定向到通过应用程序 `fortify` 配置文件中的 `home` 配置选项配置的 URI。 如果登录请求是 XHR 请求,将返回 200 HTTP 响应。
如果请求不成功,用户将被重定向回登录页,验证错误将通过共享的 `$errors` [Blade 模板变量](/docs/laravel/8.x/validation#quick-displaying-the-validation-errors) 提供给你。 或者,在 XHR 请求的情况下,验证错误将与 422 HTTP 响应一起返回。
### 自定义用户认证
Fortify 将根据提供的凭据和为您的应用程序配置的身份验证保护自动检索和验证用户。 但是,您有时可能希望对登录凭据的身份验证和用户的检索方式进行完全自定义。 幸运的是,Fortify 允许您使用 `Fortify::authenticateUsing` 方法轻松完成此操作。
此方法接受接收传入 HTTP 请求的闭包。 闭包负责验证附加到请求的登录凭据并返回关联的用户实例。 如果凭据无效或找不到用户,则闭包应返回 `null` 或 `false`。 通常,这个方法应该从你的 `FortifyServiceProvider` 的 `boot` 方法中调用:
```php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Fortify\Fortify;
/**
* 引导应用服务
*
* @return void
*/
public function boot()
{
Fortify::authenticateUsing(function (Request $request) {
$user = User::where('email', $request->email)->first();
if ($user &&
Hash::check($request->password, $user->password)) {
return $user;
}
});
// ...
}
```
#### 身份验证看守器
您可以在应用程序的 `fortify` 文件中自定义 Fortify 使用的身份验证看守器。 但是,您应该确保配置的看守器是 `Illuminate\Contracts\Auth\StatefulGuard` 的实现。 如果您尝试使用 Laravel Fortify 对 SPA 进行身份验证,您应该将 Laravel 的默认 `web` 防护与 [Laravel Sanctum](https://laravel.com/docs/sanctum) 结合使用。
## 双重认证
当 Fortify 的双重因素身份验证功能启用时,用户需要在身份验证过程中输入一个六位数的数字令牌。 此令牌是使用基于时间的一次性密码 (TOTP) 生成的,该密码可从任何与 TOTP 兼容的移动身份验证应用程序(例如 Google Authenticator)中检索。
在开始之前,你应该首先确保你的应用程序的 `App\Models\User` 模型使用 `Laravel\Fortify\TwoFactorAuthenticatable` trait:
```php
默认情况下,`fortify` 配置文件的 `features` 数组指示 Fortify 的双重因素身份验证设置在修改前需要密码确认。 因此,您的应用应提前实现 Fortify 的 [密码确认](#password-confirmation) 功能。
### 启用双重因素身份验证
要启用双重身份验证,您的应用程序应向 Fortify 定义的 `/user/two-factor-authentication` 发出 POST 请求。 如果请求成功,用户将被重定向回之前的 URL,并且 `status` session 变量将设置为 `two-factor-authentication-enabled`。 您可以在模板中检测这个 `status` session 变量以显示适当的成功消息。 如果请求是 XHR 请求,将返回 `200` HTTP 响应:
```html
@if (session('status') == 'two-factor-authentication-enabled')
Two factor authentication has been enabled.
@endif
```
接下来,您应该显示双重身份验证二维码,供用户扫描到他们的身份验证器应用程序中。 如果您使用 Blade 呈现应用程序的前端,则可以使用用户实例上可用的
`twoFactorQrCodeSvg` 方法检索二维码 SVG:
```php
$request->user()->twoFactorQrCodeSvg();
```
如果您正在构建由 JavaScript 驱动的前端,您可以向 `/user/two-factor-qr-code` 发出 XHR GET 请求以检索用户的双重身份验证二维码。 将返回一个包含 `svg` 键的 JSON 对象。
#### 显示恢复码
您还应该显示用户的双因子恢复码。 这些恢复码允许用户在无法访问其移动设备时进行身份验证。 如果您使用 Blade 呈现应用程序的前端,您可以通过经过身份验证的用户实例访问恢复码:
```php
(array) $request->user()->two_factor_recovery_codes
```
如果你正在构建一个 JavaScript 驱动的前端,你可以向 `/user/two-factor-recovery-codes` 发出 XHR GET 请求。 将返回一个包含用户恢复码的 JSON 数组。
要重新生成用户的恢复码,您的应用程序应该向 `/user/two-factor-recovery-codes` 发出 POST 请求。
### 使用双重验证
在身份验证过程中,Fortify 会自动将用户重定向到您的应用程序的双重身份的屏幕验证。但如果您的应用程序发出 XHR 登录请求,则在成功进行身份验证后返回一个包含 `two_factor` 布尔属性的 JSON 对象。 您可以检查此值以了解是否应该重定向到双重因素的屏幕验证。
要开始实现双重验证功能,我们需要指示 Fortify 如何返回双重验证的视图。 Fortify 的所有身份验证视图渲染逻辑都可以通过 Laravel\Fortify\Fortify 类使用适当的方法进行自定义。 通常,您应该从应用程序的 `App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用此类:
```php
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::twoFactorChallengeView(function () {
return view('auth.two-factor-challenge');
});
// ...
}
```
Fortify 负责定义返回此视图的 `/two-factor-challenge` 路由。 您的 `two-factor-challenge` 模板应该包括一个向 `/two-factor-challenge` 发出 POST 请求的表单。 `/two-factor-challenge` 操作需要包含有效 TOTP 令牌的 `code` 字段或包含用户恢复码之一的 `recovery_code` 字段。
如果登录成功,Fortify 会将用户重定向到通过应用程序 `fortify` 配置文件中的 `home` 配置选项配置的 URI。 如果登录请求是 XHR 请求,将返回 204 HTTP 响应。
如果请求不成功,用户将被重定向到登录界面,同时验证错误你将可以通过共享变量 `$errors` 来使用 [Blade template variable](/docs/laravel/8.x/validation#quick-displaying-the-validation-errors)。或者,在 XHR 请求中,验证错误将通过状态码 422 的 HTTP 响应返回。
### 禁用双因素认证
如果要禁用双因素认证,你的应用应该向 `/user/two-factor-authentication` 发起一个 DELETE 请求。请记住,Fortify 的双因素认证接口在 [密码确认](#password-confirmation) 期间被调用。
## 注册
为了实现应用的注册功能,我们需要指导 Fortify 如何返回我们的「注册」页面。请记住,Fortify 是一个无界面认证库。如果你想要一个已经为你完成 Laravel 的认证功能的前端实现,你可以使用 [应用入门套件](/docs/laravel/8.x/starter-kits).
所有的 Fortify 的界面渲染逻辑都可以利用合适的方法通过`Laravel\Fortify\Fortify` 类来定制。 通常,你应该在`App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用该方法。
```php
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::registerView(fn () => view('auth.register'));
// ...
}
```
Fortify 负责定义返回这个界面的 `/register` 路由。`register` 模版中应该包含一个可以由 Fortity 定义的可以发起 POST 请求到 `/register` 接口的表单。
`/register` 接口接收字符串类型 `name`,字符串类型邮箱地址/用户名、`password` 和 `password_confirmation` 字段。邮箱/用户名的字段名应该和你应用的 `fortify` 配置文件中的 `username` 配置一致。
如果注册成功,Fortify 会将用户重定向到 `fortify` 配置文件中的 `home` 项配置的 URI。如果登录是一个 XHR 请求, 将返回 200 HTTP 响应 。
如果请求不成功,用户将被重定向回注册页,验证错误将通过共享的 `$errors` [Blade 模板变量](/docs/laravel/8.x/validation#quick-displaying-the-validation-errors)。或者,对于 XHR 请求,验证错误将与 422 HTTP 响应一起返回。
### 自定义注册
可以通过修改安装 Laravel Fortify 时生成的 `App\Actions\Fortify\CreateNewUser` 操作来自定义用户验证和创建过程。
## 重设密码
### 请求密码重置链接
要想实现应用的密码重置功能,我们需要指示 Fortify 如何返回我们的 「忘记密码」视图。请记住,Fortify 是一个无标头身份验证库。如果你想要一个已经为你完成的 Laravel 身份验证功能的前端实现,你应该使用一个 [应用程序入门工具包](/docs/laravel/8.x/starter-kits)。
Fortify 的所有视图渲染逻辑都可以通过 `Laravel\Fortify\Fortify` 类使用适当的方法进行自定义。通常,您应该从应用程序的 `App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用此方法:
```php
use Laravel\Fortify\Fortify;
/**
* 引导任意应用服务
*
* @return void
*/
public function boot()
{
Fortify::requestPasswordResetLinkView(function () {
return view('auth.forgot-password');
});
// ...
}
```
Fortify 将负责定义返回此视图的 `/forgot-password` 路径。你的 `forgot-password` 模板应该包括一个向 `/forgot-password` 发出 POST 请求的表单。
`/forgot-password` 需要一个字符串 `email` 字段。此字段 / 数据库列的名称应与应用程序的 `fortify` 配置文件中的 `email` 配置值匹配。
#### 处理密码重置链接请求响应
如果密码重置链接请求成功,Fortify 会将用户重定向回 `/forgot-password` ,并向用户发送一封电子邮件,其中包含可用于重置密码的安全链接。如果请求是 XHR 请求,将返回 200 HTTP 响应。
在请求成功后被重定向回 `/forgot-password` 后,`status` session 变量可用于显示密码重置链接请求尝试的状态。此 session 变量的值将匹配应用程序的 `passwords` [语言文件](/docs/laravel/8.x/localization) 中定义的翻译字符串之一:
```html
@if (session('status'))
{{ session('status') }}
@endif
```
如果请求不成功,用户将被重定向回请求密码重置链接页面,验证错误将通过共享的 `$errors` [Blade 模板变量](/docs/laravel/8.x/validation#quick-displaying-the-validation-errors)。或者,对于 XHR 请求,验证错误将与 422 HTTP 响应一起返回。
### 重置密码
为了实现应用程序的密码重置功能,我们需要指示 Fortify 如何返回我们的「重置密码」视图。
所有的 Fortify 的界面渲染逻辑都可以利用合适的方法通过 `Laravel\Fortify\Fortify` 类来定制。 通常,你应该在 `App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用该方法。
```php
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::resetPasswordView(function ($request) {
return view('auth.reset-password', ['request' => $request]);
});
// ...
}
```
Fortify 负责定义显示这个界面的路由。 `reset-password` 模版应该包含一个向 `/reset-password` 发出 POST 请求的表单。
`/reset-password` 接口接收一个字符串类型 `email` 、`password`、`password_confirmation` 字段,和一个隐藏的名为`token` 包含 `request()->route('token')` 值的字段. 名为 "email" 字段/数据库列应该和你应用的 `fortify` 配置文件中定义的 `email` 值匹配。
#### 密码重置返回的处理
如果密码重置请求成功,Fortify 重定向回到之前的 `/login` 路由,这样用户可以使用新的密码登录。此外 `status` session 变量将被设置,这样你可以在登录界面展示那个重置成功的状态:
```html
@if (session('status'))
{{ session('status') }}
@endif
```
如果请求是一个 XHR 请求, 200 HTTP 的响应将返回。
如果请求不成功,用户将被重定向回重置密码界面,你将可以将通过共享的 `$errors` [Blade 模版变量](/docs/laravel/8.x/validation#quick-displaying-the-validation-errors) 利用验证错误。或者,对于 XHR 请求,验证错误将与 422 HTTP 响应一起返回。
### 定制密码重置
密码重置过程可以通过更改你安装 Laravel Fortify 是生成的 `App\Actions\ResetUserPassword` 动作来定制。
## 邮箱验证
在注册之后,你可能希望用户在进入应用之前能够先验证他们的邮箱。在开始之前,确保 `emailVerification` 功能在 `fortify` 配置文件的 `features`数组中是打开的 。接着,你要确保你的 `App\Models\User` 类实现了 `Illuminate\Contracts\Auth\MustVerifyEmail` 接口。
一旦完成这两步,新注册的用户将收到一个邮件引导他们验证邮箱的归属。然而,我们需要通知 Fortify 如何展示邮件验证界面,告知用户他们需要点击邮件中的验证链接。
所有的 Fortify 的界面渲染逻辑都可以利用合适的方法通过 `Laravel\Fortify\Fortify` 类来定制。 通常,你应该在 `App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用该方法。
```php
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::verifyEmailView(fn () => view('auth.verify-email'));
// ...
}
```
Fortify 负责定义用户被 Laravel 内置的 `verified` 中间件重定向到`/email/verify` 终端的路由。
你的 `verify-email` 模版应该包含提醒用户发到他们邮箱中的邮箱验证链接的提示语。
#### 重发邮箱验证链接
如果你希望,你可以添加一个按钮到你应用的 `verify-email` 模版,这可以触发一个 POST 请求到 `/email/verification-notification` 服务。 这个服务接收一个请求,一个新的验证邮箱将被发送给用户,这将允许用户获得一个新的验证链接,防止之前的验证链接意外被删除或者丢失。
如果重发验证链接的邮件是成功的,Fortify 将将用户重定向回 `/email/verify` ,并包含 `status` session 变量,这可以让你可以提醒用户这个操作是成功的。如果请求是一个 XHR 请求,202 HTTP 响应将返回:
```html
@if (session('status') == 'verification-link-sent')
A new email verification link has been emailed to you!
@endif
```
### Protecting Routes
在指定一个路由或者一组路由需要用户验证邮箱地址时,你需要将 Laravel 内置的 `verified` 中间件添加到路由上。这个中间件在应用的 `App\Http\Kernel` 类中注册:
```php
Route::get('/dashboard', function () {
// ...
})->middleware(['verified']);
```
## 密码确认
在构建应用程序时,您可能偶尔会执行一些操作,需要用户在执行操作之前确认其密码。 通常,这些路由由 Laravel 内置 `password.confirm` 中间件保护。
要开始实现密码确认功能,我们需要指示 Fortify 如何返回我们应用程序的“密码确认”视图。 请记住,Fortify 是一个无界面身份验证库。 如果你想要一个已经为你完成的 Laravel 身份验证功能的前端实现,你应该使用一个[应用入门套件](/docs/laravel/8.x/starter-kits).
Fortify 的所有视图渲染逻辑都可以通过 `Laravel\Fortify\Fortify` 类来使用适当的方法进行自定义。 通常,您应该从应用程序的 `App\Providers\FortifyServiceProvider` 类的 `boot` 方法中调用此方法:
```php
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::confirmPasswordView(function () {
return view('auth.confirm-password');
});
// ...
}
```
Fortify 将负责定义返回此视图的 `/user/confirm-password` 端点。 你的 `confirm-password` 模板应该包括一个向 `/user/confirm-password` 端点发出 POST 请求的表单。 `/user/confirm-password` 端点需要一个包含用户当前密码的 `password` 字段。
如果密码与用户的当前密码匹配,Fortify 会将用户重定向到他们试图访问的路径。 如果请求是 XHR 请求,将返回 201 HTTP 响应。
如果请求不成功,用户将被重定向回确认密码屏幕,验证错误将通过共享的 `$errors` Blade 模板变量提供给你。 如果是 XHR 请求,验证错误将与 422 HTTP 响应一起返回。