简介

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

由于 Fortify 不提供自身的用户界面,它旨在与你自己的用户界面配合使用,由你的界面向其注册的路由发起请求。在本文档的后续内容中,我们将详细介绍如何向这些路由发起请求。

请记住,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 认证路由发起请求,以完成用户认证与注册。

如果你选择手动与 Laravel 的认证服务交互而非使用 Fortify,可以按照 认证、密码重置和邮箱验证文档中的内容进行操作。

Laravel Fortify 与 Laravel Sanctum

部分开发者会对 Laravel Sanctum 与 Laravel Fortify 的区别感到困惑。由于这两个包解决的是两个不同但相关的问题,Laravel Fortify 与 Laravel Sanctum 并非互斥或竞争关系。

Laravel Sanctum 仅负责管理 API 令牌,并通过会话 Cookie 或令牌对现有用户进行认证。Sanctum 不提供任何处理用户注册、密码重置等功能的路由。

如果你正在为提供 API 或作为单页应用后端的应用手动构建认证层,完全有可能同时使用 Laravel Fortify(用于用户注册、密码重置等)与 Laravel Sanctum(API 令牌管理、会话认证)。

安装

开始使用前,通过 Composer 包管理器安装 Fortify:

composer require laravel/fortify

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

php artisan fortify:install

此命令会将 Fortify 的动作发布到你的 app/Actions 目录,若该目录不存在则会被创建。此外,FortifyServiceProvider、配置文件及所有必要的数据库迁移文件也会被发布。

之后,你应该迁移数据库:

php artisan migrate

Fortify 功能

fortify 配置文件包含一个 features 配置数组。该数组定义了 Fortify 默认暴露的后端路由 / 功能。我们建议你仅启用以下功能,即大多数 Laravel 应用提供的基础认证功能:

'features' => [
    Features::registration(),
    Features::resetPasswords(),
    Features::emailVerification(),
],

禁用视图

默认情况下,Fortify 定义了一些用于返回视图的路由,例如登录界面或注册界面。不过,如果你正在构建由 JavaScript 驱动的单页应用,可能不需要这些路由。因此,你可以在应用的 config/fortify.php 配置文件中,将 views 配置项的值设为 false,从而完全禁用这些路由:

'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 路由:

use Laravel\Fortify\Fortify;

/**
 * 引导任何应用服务。
 */
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 会根据所提供的凭据以及为应用配置的身份验证守卫(authentication guard)自动检索用户并进行身份验证。不过,有时你可能希望对登录凭据的验证方式以及用户的检索方式进行完全自定义。好在 Fortify 允许你使用 Fortify::authenticateUsing 方法轻松实现这一点。

该方法接收一个闭包,该闭包会接收传入的 HTTP 请求。该闭包负责验证附加在请求上的登录凭据,并返回关联的用户实例。如果凭据无效或找不到用户,闭包应返回 null 或 false。通常,该方法应在你的 FortifyServiceProvider 的 boot 方法中调用:

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

    // ...
}

身份验证守卫

你可以在应用的 fortify 配置文件中自定义 Fortify 使用的身份验证守卫。不过,你应确保所配置的守卫是 Illuminate\Contracts\Auth\StatefulGuard 的实现。如果你打算使用 Laravel Fortify 来验证 SPA(单页应用),应使用 Laravel 默认的 web 守卫,并配合 Laravel Sanctum 使用。

自定义身份验证管道

Laravel Fortify 通过一系列可调用类组成的管道来验证登录请求。如果需要,你可以定义一个自定义的类管道,让登录请求依次通过该管道。每个类都应有一个 __invoke 方法,该方法接收传入的 Illuminate\Http\Request 实例,并且像 中间件 一样,还有一个 $next 变量,调用该变量可将请求传递给管道中的下一个类。

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

下面的示例包含默认的管道定义,在自行修改时,你可以将其作为起点:

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 配置文件中。

综合使用限流、双因素身份验证以及外部 Web 应用防火墙(WAF),能为应用的合法用户提供最强有力的防护。

自定义重定向

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

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

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)生成的,可从任何兼容 TOTP 的移动身份验证应用(如 Google Authenticator)中获取。

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

<?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 的密码确认功能。

启用双因素身份验证

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

在选择启用双因素身份验证后,用户仍需通过提供有效的双因素身份验证代码来“确认”其双因素身份验证配置。因此,你的“成功”消息应告知用户仍需进行双因素身份验证确认:

@if (session('status') == 'two-factor-authentication-enabled')
    <div class="mb-4 font-medium text-sm">
        Please finish configuring two-factor authentication below.
    </div>
@endif

接下来,你应显示双因素身份验证二维码,以便用户将其扫描到身份验证应用中。如果你使用 Blade 渲染应用的前端,可以使用用户实例上可用的 twoFactorQrCodeSvg 方法获取二维码 SVG:

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

如果你正在构建基于 JavaScript 的前端,可以向 /user/two-factor-qr-code 端点发送 XHR GET 请求,以获取用户的双因素身份验证二维码。该端点将返回一个包含 svg 键的 JSON 对象。

确认双因素身份验证

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

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

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

如果对双因素身份验证确认端点的请求是通过 XHR 请求发起的,将返回 200 HTTP 响应。

显示恢复代码

你也应该显示用户的双因素恢复代码。这些恢复代码允许用户在失去对其移动设备的访问权限时进行身份验证。如果你使用 Blade 渲染应用程序的前端,可以通过已认证的用户实例访问恢复代码:

(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 方法中调用此方法:

use Laravel\Fortify\Fortify;

/**
 * 初始化任何应用程序服务。
 */
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 操作需要一个包含有效 TOTP 令牌的 code 字段,或者一个包含用户其中一个恢复代码的 recovery_code 字段。

如果登录尝试成功,Fortify 会将用户重定向到你应用程序的 fortify 配置文件中通过 home 配置选项所配置的 URI。如果登录请求是 XHR 请求,将返回 204 HTTP 响应。

如果请求未成功,用户将被重定向回双因素验证界面,你可以通过共享的 $errors Blade 模板变量获取验证错误。或者,在 XHR 请求的情况下,验证错误将随 422 HTTP 响应返回。

禁用双因素身份验证

要禁用双因素身份验证,你的应用程序应向 /user/two-factor-authentication 端点发起 DELETE 请求。请记住,Fortify 的双因素身份验证端点在调用前需要确认密码。

通行密钥

Fortify 支持使用 WebAuthn 进行通行密钥身份验证。通行密钥允许用户使用诸如面容 ID、触控 ID、Windows Hello 或硬件安全密钥等平台验证器,无需密码即可进行身份验证。

启用通行密钥

要开始使用,请确保在你应用程序的 fortify 配置文件中启用了 passkeys 功能:

use Laravel\Fortify\Features;

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

confirmPassword 选项用于确定 Fortify 是否要求在注册或删除通行密钥前确认密码。

接下来,请确保你应用程序的 App\Models\User 模型实现了 Laravel\Fortify\Contracts\PasskeyUser,并使用了 Laravel\Fortify\PasskeyAuthenticatable 特性:

<?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;
}

可以通过你应用程序的 config/fortify.php 文件中的 passkeys 配置数组来自定义 Fortify 的通行密钥配置选项:

'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,
],

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

relying_party_id 应与你的应用程序域名相匹配。allowed_origins 数组列出了可以完成通行密钥注册和身份验证的浏览器源。user_handle_secret 用于派生不透明的用户标识符,确保在多次通行密钥注册过程中识别出同一用户。timeout 选项控制通行密钥注册和身份验证操作可以保持活动状态的时间。

Fortify 对其通行密钥登录、确认和注册路由应用了专门的通行密钥速率限制器。如果需要,你可以使用 fortify.limiters.passkeys 配置选项以及相应的 RateLimiter::for(...) 定义进行自定义。

JavaScript 客户端

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

通过 npm 安装该包:

npm install @laravel/passkeys

然后,你可以在前端发起通行密钥注册和验证:

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

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

如果你的应用程序使用自定义的通行密钥端点 URI,你可以针对每次调用覆盖路由:

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 辅助工具。

使用通行密钥进行身份验证

要使用通行密钥对用户进行身份验证,你的应用程序应首先向 /passkeys/login/options 端点发起 GET 请求。该端点返回前端应传递给 navigator.credentials.get(...) 的 WebAuthn 验证选项。

浏览器返回凭据后,你的应用程序应向 /passkeys/login 发起 POST 请求,并携带凭据负载。你也可以包含一个布尔类型的 remember 字段。

如果请求成功,Fortify 会将用户登录到配置的保护器中,并返回以下其中之一:

  • 对于标准请求,返回重定向到预期目标的响应。
  • 对于 XHR 请求,返回一个 200 HTTP 响应,其中包含带有 redirect 键的 JSON 负载。

使用通行密钥确认密码

对于已认证的会话,Fortify 提供了通行密钥确认端点,以满足 Laravel 对当前会话的密码确认要求。

要使用通行密钥进行确认,你的应用程序应首先向 /passkeys/confirm/options 发起 GET 请求。该端点返回前端应传递给 navigator.credentials.get(...) 的 WebAuthn 验证选项。

浏览器返回凭据后,你的应用程序应向 /passkeys/confirm 发起 POST 请求,并携带凭据负载。

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

  • 对于标准请求,返回重定向到预期目标的响应。
  • 对于 XHR 请求,返回一个 200 HTTP 响应,其中包含带有 redirect 键的 JSON 负载。

注册通行密钥

若要为已认证用户注册通行密钥,你的应用应首先向 /user/passkeys/options 发起 GET 请求。该端点会返回 WebAuthn 创建选项,你的前端应将其传递给 navigator.credentials.create(...)。

当浏览器返回凭据后,你的应用应向 /user/passkeys 发起 POST 请求,请求中包含 name 字段和 credential 字段,其中 credential 字段应包含由 navigator.credentials.create(...) 返回的序列化 PublicKeyCredential 对象。

若请求成功,Fortify 将返回以下两种响应之一:

  • 对于常规请求,返回重定向响应,并在会话中设置 passkey-registered 状态。
  • 返回 200 HTTP 响应,响应体为包含 status 键的 JSON 数据,同时包含新注册通行密钥的 id 和 name。

删除通行密钥

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

若请求成功,Fortify 将返回以下两种响应之一:

  • 对于常规请求,返回重定向响应,并在会话中设置 passkey-deleted 状态。
  • 对于 XHR 请求,返回 200 HTTP 响应,响应体为包含 status 键的 JSON 数据。

注册

要开始实现我们应用的注册功能,我们需要指示 Fortify 如何返回我们的“注册”视图。请记住,Fortify 是一个无头身份验证库。如果你想要 Laravel 身份验证功能的前端实现(已为你完成),你应该使用应用入门套件。

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

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 动作来实现自定义。

密码重置

请求密码重置链接

要开始实现我们应用的密码重置功能,我们需要指示 Fortify 如何返回我们的“忘记密码”视图。请记住,Fortify 是一个无头身份验证库。如果你想要 Laravel 身份验证功能的前端实现(已为你完成),你应该使用应用入门套件。

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

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 命令进行发布:

@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 方法中调用该方法:

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 会话变量,让你能在登录页面展示重置成功的状态:

@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\Fortify\ResetUserPassword 动作来实现自定义。

邮箱验证

注册完成后,你可能希望用户在继续访问应用程序之前先验证其电子邮件地址。首先,请确保在 fortify 配置文件的 features 数组中启用了 emailVerification 功能。接下来,你应该确保你的 App\Models\User 类实现了 Illuminate\Contracts\Auth\MustVerifyEmail 接口。

完成这两步设置后,新注册用户将收到一封电子邮件,提示他们验证其电子邮件地址的所有权。不过,我们需要告知 Fortify 如何显示电子邮件验证界面,以便告知用户需要点击电子邮件中的验证链接。

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

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 响应:

@if (session('status') == 'verification-link-sent')
    <div class="mb-4 font-medium text-sm text-green-600">
        A new email verification link has been emailed to you!
    </div>
@endif

保护路由

若要指定某个路由或一组路由要求用户已验证其电子邮件地址,你应该将 Laravel 内置的 verified 中间件附加到该路由上。verified 中间件别名由 Laravel 自动注册,它是 Illuminate\Auth\Middleware\EnsureEmailIsVerified 中间件的别名:

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

密码确认

在开发应用程序的过程中,你偶尔会遇到一些操作,需要用户在执行前确认其密码。通常,这类路由由 Laravel 内置的 password.confirm 中间件进行保护。

要开始实现密码确认功能,我们需要指示 Fortify 如何返回应用程序的“密码确认”视图。请记住,Fortify 是一个无头(headless)身份验证库。如果你想使用已为你完成的 Laravel 身份验证功能的前端实现,应该使用应用程序入门套件。

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

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 响应。

如果请求未成功,用户将被重定向回密码确认界面,你可以通过共享的 Blade 模板变量 $errors 获取验证错误信息。或者,如果是 XHR 请求,验证错误将以 422 HTTP 响应的形式返回。