Skip to content

Laravel Fortify ​

简介 ​

Laravel Fortify 是 Laravel 的一个与前端无关的认证后端实现。Fortify 会注册实现 Laravel 全部认证功能所需的路由和控制器,包括登录、注册、密码重置、邮箱验证等。安装 Fortify 后,你可以运行 route:list Artisan 命令查看它注册的路由。

由于 Fortify 不提供自己的用户界面,因此它需要与你自己的 UI 搭配使用,由你的 UI 向它注册的路由发起请求。本文档后续内容会详细说明如何向这些路由发起请求。

NOTE

请记住,Fortify 是一个帮助你快速实现 Laravel 认证功能的包。你并不必须使用它。 你始终可以按照认证、重置密码和邮箱验证文档,手动与 Laravel 的认证服务交互。

什么是 Fortify? ​

如前所述,Laravel Fortify 是 Laravel 的一个与前端无关的认证后端实现。Fortify 会注册实现 Laravel 全部认证功能所需的路由和控制器,包括登录、注册、密码重置、邮箱验证等。

你并不需要使用 Fortify 才能使用 Laravel 的认证功能。 你始终可以按照认证、重置密码和邮箱验证文档,手动与 Laravel 的认证服务交互。

如果你是 Laravel 新手,可以先了解一下我们的应用程序入门套件。Laravel 的应用程序入门套件在内部使用 Fortify 为应用提供认证脚手架,其中包含基于 Tailwind CSS 构建的用户界面。这样你就可以通过实际代码学习并熟悉 Laravel 的认证功能。

Laravel Fortify 本质上是把我们的应用程序入门套件中的路由和控制器提取出来,打包成一个不包含用户界面的独立包。这样你依然可以快速搭建应用认证层的后端实现,同时不受任何特定前端方案的限制。

何时应该使用 Fortify? ​

你可能会想,什么时候适合使用 Laravel Fortify。首先,如果你正在使用 Laravel 的某个应用程序入门套件,就不需要再安装 Laravel Fortify,因为所有 Laravel 应用程序入门套件都已经使用了 Fortify,并且已经提供了完整的认证实现。

如果你没有使用应用程序入门套件,但应用需要认证功能,那么你有两个选择:手动实现应用的认证功能,或者使用 Laravel Fortify 来提供这些功能的后端实现。

如果你选择安装 Fortify,那么你的用户界面将按照本文档中的说明,向 Fortify 的认证路由发起请求,以完成用户认证和注册。

如果你选择不使用 Fortify,而是手动与 Laravel 的认证服务交互,那么你可以参考认证、重置密码和邮箱验证文档进行实现。

Laravel Fortify 与 Laravel Sanctum ​

有些开发者会混淆 Laravel Sanctum 与 Laravel Fortify 的区别。由于这两个包解决的是不同但相关的问题,因此 Laravel Fortify 和 Laravel Sanctum 既不是互斥关系,也不是竞争关系。

Laravel Sanctum 只关注 API token 的管理,以及使用会话 cookie 或 token 对已有用户进行认证。Sanctum 不提供处理用户注册、密码重置等功能的路由。

如果你正在手动构建一个应用的认证层,而这个应用既提供 API,又作为单页应用的后端,那么你完全可以同时使用 Laravel Fortify(用于用户注册、密码重置等)和 Laravel Sanctum(用于 API token 管理、会话认证)。

安装 ​

首先,使用 Composer 包管理器安装 Fortify:

shell
composer require laravel/fortify

接着,使用 fortify:install Artisan 命令发布 Fortify 的资源:

shell
php artisan fortify:install

该命令会将 Fortify 的 action 发布到你的 app/Actions 目录中;如果该目录不存在,会自动创建。此外,它还会发布 FortifyServiceProvider、配置文件以及所有必要的数据库迁移文件。

然后,你应该执行数据库迁移:

shell
php artisan migrate

Fortify 功能 ​

fortify 配置文件中包含一个 features 配置数组。该数组定义了 Fortify 默认会暴露哪些后端路由 / 功能。我们建议你只启用以下这些大多数 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 认证前端实现,应当使用应用程序入门套件。

所有认证视图的渲染逻辑,都可以通过 Laravel\Fortify\Fortify 类提供的相应方法进行自定义。通常,你应该在应用的 App\Providers\FortifyServiceProvider 类的 boot 方法中调用这些方法。Fortify 会负责定义返回该视图的 /login 路由:

php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::loginView(function () {
        return view('auth.login');
    });

    // ...
}

你的登录模板应包含一个向 /login 发起 POST 请求的表单。/login 端点要求提供字符串类型的 email / username 和 password。邮箱 / 用户名字段的名称应与 config/fortify.php 配置文件中的 username 配置值一致。另外,还可以提供一个布尔类型的 remember 字段,表示用户希望启用 Laravel 提供的“记住我”功能。

如果登录成功,Fortify 会将你重定向到应用 fortify 配置文件中 home 配置项指定的 URI。如果登录请求是 XHR 请求,则会返回 200 HTTP 响应。

如果请求失败,用户会被重定向回登录页,并且你可以通过共享的 $errors Blade 模板变量 获取验证错误。或者,在 XHR 请求场景下,验证错误会通过 422 HTTP 响应返回。

自定义用户认证 ​

Fortify 会根据提供的凭据以及应用配置的认证 guard,自动检索并认证用户。不过,有时你可能希望完全自定义登录凭据的认证方式以及用户的检索逻辑。幸运的是,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;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::authenticateUsing(function (Request $request) {
        $user = User::where('email', $request->email)->first();

        if ($user &&
            Hash::check($request->password, $user->password)) {
            return $user;
        }
    });

    // ...
}

Authentication Guard ​

你可以在应用的 fortify 配置文件中自定义 Fortify 使用的认证 guard。不过,你应确保配置的 guard 是 Illuminate\Contracts\Auth\StatefulGuard 的实现。如果你打算使用 Laravel Fortify 为 SPA 提供认证,那么应将 Laravel 默认的 web guard 与 Laravel Sanctum 搭配使用。

自定义认证管道 ​

Laravel Fortify 会通过一个由可调用类组成的管道来处理登录请求。如果你愿意,也可以定义一个自定义类管道,让登录请求依次通过。每个类都应有一个 __invoke 方法,用于接收传入的 Illuminate\Http\Request 实例,以及一个类似中间件中的 $next 变量,用于将请求传给管道中的下一个类。

要定义自定义管道,你可以使用 Fortify::authenticateThrough 方法。该方法接收一个闭包,闭包应返回一个类数组,表示登录请求将依次通过的类。通常,该方法应在应用的 App\Providers\FortifyServiceProvider 类的 boot 方法中调用。

下面的示例展示了默认管道定义,你可以在此基础上进行修改:

php
use Laravel\Fortify\Actions\AttemptToAuthenticate;
use Laravel\Fortify\Actions\CanonicalizeUsername;
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;

Fortify::authenticateThrough(function (Request $request) {
    return array_filter([
            config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
            config('fortify.lowercase_usernames') ? CanonicalizeUsername::class : null,
            Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
            AttemptToAuthenticate::class,
            PrepareAuthenticatedSession::class,
    ]);
});

认证限流 ​

默认情况下,Fortify 会使用 EnsureLoginIsNotThrottled 中间件对认证尝试进行限流。该中间件会针对用户名和 IP 地址的组合进行限流。

某些应用可能需要不同的限流策略,例如仅按 IP 地址限流。因此,Fortify 允许你通过 fortify.limiters.login 配置项指定自己的速率限制器。当然,这个配置项位于应用的 config/fortify.php 配置文件中。

NOTE

同时结合限流、双因素认证和外部 Web 应用防火墙(WAF),将为你的真实应用用户提供更强的防护能力。

自定义重定向 ​

如果登录成功,Fortify 会将你重定向到应用 fortify 配置文件中 home 配置项指定的 URI。如果登录请求是 XHR 请求,则会返回 200 HTTP 响应。用户从应用中登出后,会被重定向到 / URI。

如果你需要更高级的自定义行为,可以将 LoginResponse 和 LogoutResponse 契约的实现绑定到 Laravel 的 service container 中。通常,这应在应用的 App\Providers\FortifyServiceProvider 类的 register 方法中完成:

php
use Laravel\Fortify\Contracts\LogoutResponse;

/**
 * Register any application services.
 */
public function register(): void
{
    $this->app->instance(LogoutResponse::class, new class implements LogoutResponse {
        public function toResponse($request)
        {
            return redirect('/');
        }
    });
}

双因素认证 ​

启用 Fortify 的双因素认证功能后,用户在认证过程中需要输入一个六位数字令牌。该令牌基于 TOTP(基于时间的一次性密码)生成,可通过 Google Authenticator 等兼容 TOTP 的移动认证应用获取。

在开始之前,你首先应确保应用的 App\Models\User 模型使用了 Laravel\Fortify\TwoFactorAuthenticatable trait:

php
<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;

class User extends Authenticatable
{
    use Notifiable, TwoFactorAuthenticatable;
}

接下来,你应在应用中构建一个界面,让用户可以管理双因素认证设置。这个界面应允许用户启用和禁用双因素认证,以及重新生成双因素认证恢复代码。

默认情况下,fortify 配置文件中的 features 数组会要求修改双因素认证设置前先进行密码确认。因此,在继续之前,你的应用应先实现 Fortify 的密码确认功能。

启用双因素认证 ​

要开始启用双因素认证,你的应用应向 Fortify 定义的 /user/two-factor-authentication 端点发起 POST 请求。如果请求成功,用户会被重定向回之前的 URL,并且 status 会话变量会被设置为 two-factor-authentication-enabled。你可以在模板中检测该 status 会话变量,以显示相应的成功消息。如果请求是 XHR 请求,则会返回 200 HTTP 响应。

当用户选择启用双因素认证后,仍然必须通过提供有效的双因素认证代码来“确认”双因素认证配置。因此,你的“成功”消息应提示用户仍需完成双因素认证确认:

html
@if (session('status') == 'two-factor-authentication-enabled')
    <div class="mb-4 font-medium text-sm">
        请在下方完成双因素认证配置。
    </div>
@endif

接下来,你应向用户显示双因素认证二维码,以便用户使用认证器应用扫描。如果你使用 Blade 渲染应用前端,可以通过用户实例上的 twoFactorQrCodeSvg 方法获取二维码 SVG:

php
$request->user()->twoFactorQrCodeSvg();

如果你构建的是 JavaScript 驱动的前端,则可以向 /user/two-factor-qr-code 端点发起 XHR GET 请求,以获取用户的双因素认证二维码。该端点会返回一个包含 svg 键的 JSON 对象。

确认双因素认证 ​

除了显示用户的双因素认证二维码外,你还应提供一个文本输入框,让用户输入有效的认证代码来“确认”双因素认证配置。该代码应通过 POST 请求发送到 Fortify 定义的 /user/confirmed-two-factor-authentication 端点。

如果请求成功,用户会被重定向回之前的 URL,并且 status 会话变量会被设置为 two-factor-authentication-confirmed:

html
@if (session('status') == 'two-factor-authentication-confirmed')
    <div class="mb-4 font-medium text-sm">
        双因素认证已成功确认并启用。
    </div>
@endif

如果这个双因素认证确认请求是通过 XHR 发起的,则会返回 200 HTTP 响应。

显示恢复代码 ​

你还应显示用户的双因素认证恢复代码。如果用户失去了对移动设备的访问权限,这些恢复代码可以帮助其完成认证。如果你使用 Blade 渲染应用前端,可以通过已认证用户实例访问恢复代码:

php
(array) $request->user()->recoveryCodes();

如果你构建的是 JavaScript 驱动的前端,则可以向 /user/two-factor-recovery-codes 端点发起 XHR GET 请求。该端点会返回一个包含用户恢复代码的 JSON 数组。

要重新生成用户的恢复代码,你的应用应向 /user/two-factor-recovery-codes 端点发起 POST 请求。

使用双因素认证进行登录 ​

在认证过程中,Fortify 会自动将用户重定向到应用的双因素认证挑战界面。不过,如果你的应用发起的是 XHR 登录请求,那么在认证尝试成功后返回的 JSON 响应中,会包含一个带有 two_factor 布尔属性的 JSON 对象。你应检查该值,以判断是否需要将用户重定向到应用的双因素认证挑战界面。

要开始实现双因素认证功能,我们需要告诉 Fortify 如何返回双因素认证挑战视图。所有 Fortify 认证视图的渲染逻辑,都可以通过 Laravel\Fortify\Fortify 类提供的相应方法进行自定义。通常,该方法应在应用 App\Providers\FortifyServiceProvider 类的 boot 方法中调用:

php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::twoFactorChallengeView(function () {
        return view('auth.two-factor-challenge');
    });

    // ...
}

Fortify 会负责定义返回该视图的 /two-factor-challenge 路由。你的 two-factor-challenge 模板应包含一个向 /two-factor-challenge 端点发起 POST 请求的表单。/two-factor-challenge action 期望接收一个包含有效 TOTP token 的 code 字段,或一个包含用户某个恢复代码的 recovery_code 字段。

如果登录成功,Fortify 会将用户重定向到应用 fortify 配置文件中 home 配置项指定的 URI。如果登录请求是 XHR 请求,则会返回 204 HTTP 响应。

如果请求失败,用户会被重定向回双因素认证挑战界面,并且你可以通过共享的 $errors Blade 模板变量 获取验证错误。或者,在 XHR 请求场景下,验证错误会通过 422 HTTP 响应返回。

禁用双因素认证 ​

要禁用双因素认证,你的应用应向 /user/two-factor-authentication 端点发起 DELETE 请求。请记住,在调用 Fortify 的双因素认证端点之前,必须先通过密码确认。

Passkey 认证 ​

Fortify 支持使用 WebAuthn 进行 passkey 认证。Passkey 允许用户通过 Face ID、Touch ID、Windows Hello 或硬件安全密钥等平台认证器,在无需密码的情况下完成认证。

启用 Passkey ​

首先,请确保应用 fortify 配置文件中已启用 passkeys 功能:

php
use Laravel\Fortify\Features;

'features' => [
    // ...
    Features::passkeys([
        'confirmPassword' => true,
    ]),
],

confirmPassword 选项决定 Fortify 是否要求在注册或删除 passkey 前先完成密码确认。

接下来,请确保应用的 App\Models\User model 实现了 Laravel\Fortify\Contracts\PasskeyUser,并使用 Laravel\Fortify\PasskeyAuthenticatable trait:

php
<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\Contracts\PasskeyUser;
use Laravel\Fortify\PasskeyAuthenticatable;

class User extends Authenticatable implements PasskeyUser
{
    use Notifiable, PasskeyAuthenticatable;
}

Fortify 的 passkeys 配置选项可通过应用 config/fortify.php 文件中的 passkeys 配置数组进行自定义:

php
'passkeys' => [
    'relying_party_id' => parse_url(config('app.url'), PHP_URL_HOST),
    'allowed_origins' => [config('app.url')],
    'user_handle_secret' => config('app.key'),
    'timeout' => 60000,
],

NOTE

Fortify 会封装 laravel/passkeys Composer 包,并为你完成配置。如果你使用 Fortify 的 passkeys 功能,应通过应用的 config/fortify.php 文件配置 passkeys。你无需发布 laravel/passkeys 配置文件,并且其中定义的任何值都会被 Fortify 覆盖。

relying_party_id 应与应用的域名匹配。allowed_origins 数组列出了允许完成 passkey 注册和认证的浏览器 origin。user_handle_secret 用于派生不透明的用户标识符,确保同一用户在多次 passkey 注册中都能被识别。timeout 选项控制 passkey 注册和认证操作可以保持活动的时长。

Fortify 会对 passkey 登录、确认和注册路由应用专用的 passkeys 速率限制器。需要时,你可以通过 fortify.limiters.passkeys 配置选项和对应的 RateLimiter::for(...) 定义对其进行自定义。

JavaScript 客户端 ​

如果你正在构建自定义前端,包括带有浏览器端脚本的 Blade 应用,可以使用官方 @laravel/passkeys 包。该包会处理浏览器 WebAuthn 流程,并向 Fortify 的 passkey 端点发送请求。

通过 npm 安装该包:

shell
npm install @laravel/passkeys

然后,你可以从前端发起 passkey 注册和验证:

js
import { Passkeys } from "@laravel/passkeys";

await Passkeys.register({ name: "MacBook Pro" });
await Passkeys.verify();

如果应用使用了自定义的 passkey 端点 URI,你可以在每次调用时覆盖路由:

js
await Passkeys.verify({
    routes: {
        options: "/passkeys/confirm/options",
        submit: "/passkeys/confirm",
    },
});

await Passkeys.register({
    name: "MacBook Pro",
    routes: {
        options: "/user/passkeys/options",
        submit: "/user/passkeys",
    },
});

该包还通过 @laravel/passkeys/react、@laravel/passkeys/vue 和 @laravel/passkeys/svelte 提供 React、Vue 与 Svelte helper。

使用 Passkey 进行认证 ​

要使用 passkey 认证用户,你的应用应先向 /passkeys/login/options 端点发起 GET 请求。该端点会返回 WebAuthn challenge 选项,前端应将这些选项传递给 navigator.credentials.get(...)。

浏览器返回 credential 后,你的应用应向 /passkeys/login 发起 POST 请求,并携带 credential payload。你还可以包含一个布尔类型的 remember 字段。

如果请求成功,Fortify 会将用户登录到配置的 guard,并返回以下响应之一:

  • 对于标准请求,返回重定向到预期目标位置的响应。
  • 对于 XHR 请求,返回包含 redirect 键的 JSON payload 和 200 HTTP 响应。

使用 Passkey 确认密码 ​

对于已认证的 session,Fortify 提供了 passkey 确认端点,用于满足当前 session 的 Laravel 密码确认要求。

要通过 passkey 进行确认,你的应用应先向 /passkeys/confirm/options 发起 GET 请求。该端点会返回 WebAuthn challenge 选项,前端应将这些选项传递给 navigator.credentials.get(...)。

浏览器返回 credential 后,你的应用应向 /passkeys/confirm 发起 POST 请求,并携带 credential payload。

如果请求成功,Fortify 会将当前 session 标记为已完成密码确认,并返回以下响应之一:

  • 对于标准请求,返回重定向到预期目标位置的响应。
  • 对于 XHR 请求,返回包含 redirect 键的 JSON payload 和 200 HTTP 响应。

注册 Passkey ​

要为已认证用户注册 passkey,你的应用应先向 /user/passkeys/options 发起 GET 请求。该端点会返回 WebAuthn creation 选项,前端应将这些选项传递给 navigator.credentials.create(...)。

浏览器返回 credential 后,你的应用应向 /user/passkeys 发起 POST 请求,并携带 name 字段,以及一个包含 navigator.credentials.create(...) 返回的序列化 PublicKeyCredential 对象的 credential 字段。

如果请求成功,Fortify 会返回以下响应之一:

  • 对于标准请求,返回带有 session 状态 passkey-registered 的 redirect back 响应。
  • 返回包含 status 键以及新注册 passkey 的 id 和 name 的 JSON payload 和 200 HTTP 响应。

删除 Passkey ​

要删除 passkey,你的应用应向 /user/passkeys/{passkey} 发起 DELETE 请求。

如果请求成功,Fortify 会返回以下响应之一:

  • 对于标准请求,返回带有 session 状态 passkey-deleted 的 redirect back 响应。
  • 对于 XHR 请求,返回包含 status 键的 JSON payload 和 200 HTTP 响应。

注册 ​

要开始实现应用的注册功能,我们需要告诉 Fortify 如何返回“注册”视图。请记住,Fortify 是一个无头认证库。如果你希望直接使用一套已经完成的 Laravel 认证前端实现,应当使用应用程序入门套件。

Fortify 的所有视图渲染逻辑,都可以通过 Laravel\Fortify\Fortify 类提供的相应方法进行自定义。通常,该方法应在你的 App\Providers\FortifyServiceProvider 类的 boot 方法中调用:

php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::registerView(function () {
        return view('auth.register');
    });

    // ...
}

Fortify 会负责定义返回该视图的 /register 路由。你的 register 模板应包含一个向 Fortify 定义的 /register 端点发起 POST 请求的表单。

/register 端点要求提供字符串类型的 name、邮箱地址 / 用户名字符串、password 和 password_confirmation 字段。邮箱 / 用户名字段的名称应与应用 fortify 配置文件中定义的 username 配置值一致。

如果注册成功,Fortify 会将用户重定向到应用 fortify 配置文件中 home 配置项指定的 URI。如果请求是 XHR 请求,则会返回 201 HTTP 响应。

如果请求失败,用户会被重定向回注册页面,并且你可以通过共享的 $errors Blade 模板变量 获取验证错误。或者,在 XHR 请求场景下,验证错误会通过 422 HTTP 响应返回。

自定义注册 ​

用户验证和创建流程可以通过修改你在安装 Laravel Fortify 时生成的 App\Actions\Fortify\CreateNewUser action 来进行自定义。

重置密码 ​

要开始实现应用的密码重置功能,我们需要告诉 Fortify 如何返回“忘记密码”视图。请记住,Fortify 是一个无头认证库。如果你希望直接使用一套已经完成的 Laravel 认证前端实现,应当使用应用程序入门套件。

Fortify 的所有视图渲染逻辑,都可以通过 Laravel\Fortify\Fortify 类提供的相应方法进行自定义。通常,该方法应在应用 App\Providers\FortifyServiceProvider 类的 boot 方法中调用:

php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    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 会话变量显示本次密码重置链接请求的状态。

$status 会话变量的值将对应应用 passwords 语言文件中定义的某个翻译字符串。如果你想自定义这个值,而此前又没有发布 Laravel 的语言文件,可以通过 lang:publish Artisan 命令完成:

html
@if (session('status'))
    <div class="mb-4 font-medium text-sm text-green-600">
        {{ session('status') }}
    </div>
@endif

如果请求失败,用户会被重定向回“请求密码重置链接”页面,并且你可以通过共享的 $errors Blade 模板变量 获取验证错误。或者,在 XHR 请求场景下,验证错误会通过 422 HTTP 响应返回。

重置密码 ​

要完成应用的密码重置功能实现,我们需要告诉 Fortify 如何返回“重置密码”视图。

Fortify 的所有视图渲染逻辑,都可以通过 Laravel\Fortify\Fortify 类提供的相应方法进行自定义。通常,该方法应在应用 App\Providers\FortifyServiceProvider 类的 boot 方法中调用:

php
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Fortify::resetPasswordView(function (Request $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 会话变量,以便你在登录页面显示密码重置成功的状态:

blade
@if (session('status'))
    <div class="mb-4 font-medium text-sm text-green-600">
        {{ session('status') }}
    </div>
@endif

如果请求是 XHR 请求,则会返回 200 HTTP 响应。

如果请求失败,用户会被重定向回重置密码页面,并且你可以通过共享的 $errors Blade 模板变量 获取验证错误。或者,在 XHR 请求场景下,验证错误会通过 422 HTTP 响应返回。

自定义密码重置 ​

密码重置流程可以通过修改你在安装 Laravel Fortify 时生成的 App\Actions\ResetUserPassword action 来进行自定义。

邮箱验证 ​

注册完成后,你可能希望要求用户在继续访问应用之前先验证邮箱地址。首先,请确保 fortify 配置文件 features 数组中启用了 emailVerification 功能。接着,你应确保 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.
 */
public function boot(): void
{
    Fortify::verifyEmailView(function () {
        return view('auth.verify-email');
    });

    // ...
}

当用户被 Laravel 内置的 verified 中间件重定向到 /email/verify 端点时,Fortify 会负责定义显示该视图的路由。

你的 verify-email 模板应包含一条提示信息,告知用户点击发送到其邮箱地址中的验证链接。

如果需要,你可以在应用的 verify-email 模板中添加一个按钮,让它向 /email/verification-notification 端点发起 POST 请求。当该端点收到请求后,会向用户发送一封新的验证邮件,使用户在之前的验证链接被误删或丢失时,可以重新获取一个新的链接。

如果重新发送验证链接邮件的请求成功,Fortify 会将用户重定向回 /email/verify 端点,并附带一个 status 会话变量,以便你向用户显示操作成功的提示信息。如果请求是 XHR 请求,则会返回 202 HTTP 响应:

blade
@if (session('status') == 'verification-link-sent')
    <div class="mb-4 font-medium text-sm text-green-600">
        已向你的邮箱发送新的邮箱验证链接!
    </div>
@endif

保护路由 ​

如果你想指定某个路由或某组路由必须要求用户先验证邮箱地址后才能访问,应为该路由附加 Laravel 内置的 verified 中间件。verified 中间件别名会由 Laravel 自动注册,它实际上是 Illuminate\Auth\Middleware\EnsureEmailIsVerified 中间件的别名:

php
Route::get('/dashboard', function () {
    // ...
})->middleware(['verified']);

密码确认 ​

在构建应用时,你可能偶尔会有一些操作,需要用户在执行之前再次确认密码。通常,这些路由会受到 Laravel 内置 password.confirm 中间件的保护。

要开始实现密码确认功能,我们需要告诉 Fortify 如何返回应用的“确认密码”视图。请记住,Fortify 是一个无头认证库。如果你希望直接使用一套已经完成的 Laravel 认证前端实现,应当使用应用程序入门套件。

Fortify 的所有视图渲染逻辑,都可以通过 Laravel\Fortify\Fortify 类提供的相应方法进行自定义。通常,该方法应在应用 App\Providers\FortifyServiceProvider 类的 boot 方法中调用:

php
use Laravel\Fortify\Fortify;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    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 响应返回。