> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Fortify 與啟動套件

> 說明前端無關的驗證後端 Laravel Fortify 的內部設計。涵蓋現行啟動套件為何使用 Fortify、FortifyServiceProvider 的設定，以及 2FA、Passkey 的啟用。

## 什麼是 Fortify

[Laravel Fortify](https://github.com/laravel/fortify) 是與前端無關的驗證後端實作。提供登入、註冊、密碼重設、Email 驗證、2FA、Passkey 所需的所有路由與 Controller。

<Info>
  Fortify 不含 UI。它透過從啟動套件或自訂 UI 對 Fortify 路由送出請求來運作。
</Info>

「前端無關」的設計思維非常重要。Blade、Inertia（React/Vue/Svelte）、API 等，各種前端 stack 都可以重複使用同一個驗證後端。這也是 Fortify 得以長期沿用的原因。

## 歷史：從 Jetstream 到現行啟動套件

```mermaid theme={null}
timeline
    title Fortify 的變遷
    2020 Laravel 8 : 與 Jetstream 同時登場
               : Fortify 作為 Jetstream 的後台自動安裝
    2020 Laravel 8 : Breeze 登場（不含 Fortify）
               : 作為簡潔的驗證 scaffold 獨立存在
    2025 啟動套件更新 : React/Vue 啟動套件需要 2FA 支援
                         : 再度採用 Fortify → 整個驗證改採 Fortify 為基礎
    2026 Passkey 支援 : Fortify 加入 Passkeys 功能
```

### 為什麼現行啟動套件仍使用 Fortify

最初的 React/Vue 啟動套件並未使用 Fortify 實作。但**當需要支援雙因素驗證（2FA）時，Fortify 被直接採用**，整個驗證便切換為 Fortify 為基礎。

Fortify 因設計為「前端無關」，與使用 Inertia 的啟動套件契合度高，也因此持續被使用至今。

<Info>
  Fortify 目前是持續使用時間最長的 Laravel 官方驗證套件。自 2020 年登場以來，從 Jetstream → 現行啟動套件不斷變換形式，仍持續在現役。
</Info>

## 現行啟動套件的結構

在 React/Vue 啟動套件中，以下檔案設定了 Fortify。

* `app/Providers/FortifyServiceProvider.php` — 檢視、動作、速率限制的註冊
* `config/fortify.php` — 要啟用的功能與驗證設定

### `config/fortify.php` 的主要設定

```php theme={null}
use Laravel\Fortify\Features;

return [
    'guard'    => 'web',
    'username' => 'email',
    'home'     => '/dashboard',

    'limiters' => [
        'login'      => 'login',
        'two-factor' => 'two-factor',
    ],

    'features' => [
        Features::registration(),
        Features::resetPasswords(),
        Features::emailVerification(),
        Features::twoFactorAuthentication([
            'confirm'         => true,
            'confirmPassword' => true,
        ]),
    ],
];
```

在啟動套件中，Passkey（`Features::passkeys()`）預設並未啟用。要啟用需新增至 `features` 陣列。

## `FortifyServiceProvider` 的設定

啟動套件的 `FortifyServiceProvider` 擔負 3 個角色。

### 1. 設定 Action

```php theme={null}
private function configureActions(): void
{
    Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
    Fortify::createUsersUsing(CreateNewUser::class);
}
```

透過置於 `app/Actions/Fortify/` 的類別，可自訂使用者建立與密碼重設的邏輯。驗證與雜湊處理集中於此。

### 2. 設定 View

```php theme={null}
private function configureViews(): void
{
    Fortify::loginView(fn (Request $request) => Inertia::render('auth/login', [
        'canResetPassword' => Features::enabled(Features::resetPasswords()),
        'canRegister'      => Features::enabled(Features::registration()),
        'status'           => $request->session()->get('status'),
    ]));

    Fortify::resetPasswordView(fn (Request $request) => Inertia::render('auth/reset-password', [
        'email' => $request->email,
        'token' => $request->route('token'),
    ]));

    Fortify::requestPasswordResetLinkView(
        fn (Request $request) => Inertia::render('auth/forgot-password', [
            'status' => $request->session()->get('status'),
        ])
    );

    Fortify::verifyEmailView(
        fn (Request $request) => Inertia::render('auth/verify-email', [
            'status' => $request->session()->get('status'),
        ])
    );

    Fortify::registerView(fn () => Inertia::render('auth/register'));

    Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/two-factor-challenge'));

    Fortify::confirmPasswordView(fn () => Inertia::render('auth/confirm-password'));
}
```

各檢視方法接受回傳 Inertia 元件的 closure。以 `Features::enabled()` 確認功能旗標並傳入檢視是重點。

<Info>
  在 Blade 應用程式中，將 `Inertia::render(...)` 替換為 `view('auth.login')` 回傳即可。即便更換前端，只要修改 `FortifyServiceProvider` 端即可，驗證邏輯不變。
</Info>

### 3. 設定速率限制

```php theme={null}
private function configureRateLimiting(): void
{
    RateLimiter::for('two-factor', function (Request $request) {
        return Limit::perMinute(5)->by($request->session()->get('login.id'));
    });

    RateLimiter::for('login', function (Request $request) {
        $throttleKey = Str::transliterate(
            Str::lower($request->input(Fortify::username())) . '|' . $request->ip()
        );

        return Limit::perMinute(5)->by($throttleKey);
    });
}
```

* `login` limiter：以 Email 與 IP 位址的組合限制（暴力破解對策）
* `two-factor` limiter：以 session 內的登入嘗試 ID 限制

在 `RateLimiter::for()` 註冊與 `config/fortify.php` 之 `limiters` key 相符的 key。

## 主要功能與註冊的路由

以下依功能整理 Fortify 註冊的主要路由。

| 功能            | 方法                        | 路由                                 |
| ------------- | ------------------------- | ---------------------------------- |
| 登入            | `GET`                     | `/login`                           |
| 登入            | `POST`                    | `/login`                           |
| 登出            | `POST`                    | `/logout`                          |
| 註冊            | `GET`                     | `/register`                        |
| 註冊            | `POST`                    | `/register`                        |
| 密碼重設請求        | `GET` / `POST`            | `/forgot-password`                 |
| 密碼重設          | `GET` / `POST`            | `/reset-password`                  |
| Email 驗證      | `GET`                     | `/email/verify`                    |
| Email 驗證連結重寄  | `POST`                    | `/email/verification-notification` |
| 密碼確認          | `GET` / `POST`            | `/user/confirm-password`           |
| 啟用 2FA        | `POST`                    | `/user/two-factor-authentication`  |
| 2FA challenge | `GET` / `POST`            | `/two-factor-challenge`            |
| Passkey 登入    | `GET` / `POST`            | `/passkeys/login`                  |
| Passkey 管理    | `GET` / `POST` / `DELETE` | `/user/passkeys`                   |

以 `php artisan route:list --name=fortify` 或直接使用 `php artisan route:list` 可確認實際註冊的路由。

## 雙因素驗證（2FA）

啟動套件中已啟用 `Features::twoFactorAuthentication()`。`confirm` 與 `confirmPassword` 皆設為 `true`。

| 選項                | 意義               |
| ----------------- | ---------------- |
| `confirm`         | 啟用後要求以驗證碼確認      |
| `confirmPassword` | 變更 2FA 設定前要求密碼確認 |

於 2FA 設定畫面中，使用者可以進行下列操作。

<Steps>
  <Step title="啟用 2FA">
    對 `/user/two-factor-authentication` 送出 POST 請求。成功後 session 中會設定 `two-factor-authentication-enabled` 狀態。
  </Step>

  <Step title="確認 QR code">
    對 `/user/two-factor-qr-code` 送出 GET 請求，會回傳供驗證 App 讀取的 QR code SVG。
  </Step>

  <Step title="以驗證碼確認">
    對 `/user/confirmed-two-factor-authentication` 以 POST 送出驗證碼以完成設定。
  </Step>

  <Step title="保存 Recovery Code">
    對 `/user/two-factor-recovery-codes` 送出 GET 請求取得 Recovery Code，並保存於安全處。
  </Step>
</Steps>

## Passkey

Passkey 是 Fortify 較新加入的功能。這是使用 WebAuthn 的無密碼驗證，支援 Face ID、Touch ID、Windows Hello 與硬體 Security Key。

### 啟用

於 `config/fortify.php` 的 `features` 陣列加入。

```php theme={null}
'features' => [
    Features::registration(),
    Features::resetPasswords(),
    Features::emailVerification(),
    Features::twoFactorAuthentication([
        'confirm'         => true,
        'confirmPassword' => true,
    ]),
    Features::passkeys([
        'confirmPassword' => true,
    ]),
],
```

接著在 `User` 模型加入 `PasskeyUser` contract 與 `PasskeyAuthenticatable` trait。

```php theme={null}
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Fortify\Contracts\PasskeyUser;
use Laravel\Fortify\PasskeyAuthenticatable;

class User extends Authenticatable implements PasskeyUser
{
    use PasskeyAuthenticatable;
}
```

WebAuthn 設定於 `config/fortify.php` 的 `passkeys` key 管理。

```php theme={null}
'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,
],
```

<Info>
  Fortify 的 Passkey 內部包裝了 `laravel/passkeys` Composer 套件。無需公開 `laravel/passkeys` 的設定檔，會以 `config/fortify.php` 的 `passkeys` key 為優先。
</Info>

有關 Passkey 詳細實作（`@laravel/passkeys` JS Client、React/Vue/Svelte helper 等），請參考[Passkey 初步調查](/zh-TW/blog/passkeys-introduction)。

## 相關頁面

<Card title="自訂驗證 Guard" icon="shield" href="/zh-TW/advanced/custom-auth-guard">
  說明如何實作 Guard、StatefulGuard 介面以建立自訂驗證 Guard。
</Card>

<Card title="官方文件：Laravel Fortify" icon="book-open" href="https://laravel.com/docs/fortify">
  安裝、全部功能與自訂細節請參考官方文件。
</Card>


## Related topics

- [Laravel 啟動套件的建立方式](/zh-TW/advanced/starter-kit-creation.md)
- [Laravel Maestro — 啟動套件開發的協調器](/zh-TW/blog/maestro-introduction.md)
- [Laravel Chisel — 啟動套件的安裝後腳本函式庫](/zh-TW/blog/chisel-introduction.md)
- [Laravel PAO — 針對 AI Agent 的輸出最佳化工具](/zh-TW/blog/pao-introduction.md)
- [用 Inertia.js 建構 SPA](/zh-TW/blog/inertia-introduction.md)
