Skip to content

Laravel Fortify

简介

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

由于 Fortify 不提供自己的用户界面,它旨在与您自己的用户界面配对使用,您的用户界面向其注册的路由发送请求。我们将在本文档的其余部分详细讨论如何向这些路由发送请求。

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 认证路由发送请求,以认证和注册用户。

如果您选择手动与 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:

shell
composer require laravel/fortify

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

shell
php artisan fortify:install

此命令将把 Fortify 的操作发布到您的 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;

/**
 * 引导任何应用程序服务。
 */
public function boot(): void
{
    Fortify::loginView(function () {
        return view('auth.login');
    });

    // ...
}

您的登录模板应包含一个向 /login 发送 POST 请求的表单。/login 端点需要一个字符串 email/username 和一个 password。email/username 字段的名称应与 config/fortify.php 配置文件中的 username 值匹配。此外,可以提供一个布尔 remember 字段,以指示用户希望使用 Laravel 提供的「记住我」功能。

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

如果请求不成功,用户将被重定向回登录屏幕,验证错误将通过共享的 $errors Blade 模板变量提供给您。或者,对于 XHR 请求,验证错误将随 422 HTTP 响应返回。

自定义用户认证

Fortify 将根据提供的凭据和为您的应用程序配置的认证守卫自动检索和认证用户。但是,有时您可能希望完全自定义登录凭据的认证方式和用户的检索方式。幸运的是,Fortify 允许您使用 Fortify::authenticateUsing 方法轻松实现这一点。

此方法接受一个接收传入 HTTP 请求的闭包。闭包负责验证附加到请求的登录凭据并返回关联的用户实例。如果凭据无效或找不到用户,闭包应返回 nullfalse。通常,此方法应从 FortifyServiceProviderboot 方法调用:

php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Fortify\Fortify;

/**
 * 引导任何应用程序服务。
 */
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 方法调用。

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

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。

如果您需要对此行为进行高级自定义,可以将 LoginResponseLogoutResponse 合约的实现绑定到 Laravel 服务容器中。通常,这应该在应用程序的 App\Providers\FortifyServiceProvider 类的 register 方法中完成:

php
use Laravel\Fortify\Contracts\LogoutResponse;

/**
 * 注册任何应用程序服务。
 */
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 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 的密码确认功能。

启用双因素认证

要开始启用双因素认证,您的应用程序应向 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 对象。

确认双因素认证

除了显示用户的双因素认证二维码外,您还应提供一个文本输入框,用户可以在其中提供有效的认证代码以「确认」他们的双因素认证配置。此代码应通过向 Fortify 定义的 /user/confirmed-two-factor-authentication 端点发送 POST 请求提供给 Laravel 应用程序。

如果请求成功,用户将被重定向回之前的 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()