Laravel9でFortifyを使用する

# はじめに
Laravelの認証ライブラリのFortifyについて、
基本的な設定 + カスタマイズ方法を書いていきたいと思います。

バックエンドのみで使用する想定です。

▼基本的な設定
* [1. インストールする](#1-インストールする)
* [2. Fortifyで使用するファイルを作成する](#2-fortifyで使用するファイルを作成する)
* [3. サービスプロバイダを登録する](#3-サービスプロバイダを登録する)
* [4. 各認証機能のON/OFFを切り替える](#4-各認証機能のonoffを切り替える)
* [5. ビュー用のルーティングを無効化する](#5-ビュー用のルーティングを無効化する)
* [6. ルーティングのURIにプレフィックスを追加する](#6-ルーティングのurlにプレフィックスを追加する)

▼カスタマイズ方法
* [7. 各認証機能のカスタマイズ](#7-各認証機能のカスタマイズ)
* [8. ルーティングのカスタマイズ](#8-ルーティングのカスタマイズ)

# Fortifyとは
>前述のように、Laravel FortifyはLaravelのフロントエンドに依存しない認証バックエンドの実装です。Fortifyは、ログイン、ユーザー登録、パスワードのリセット、メールの検証など、Laravelのすべての認証機能を実装するために必要なルートとコントローラを登録します。

上記は公式ドキュメントからの引用になります。
`Laravel UI`や`Laravel Breeze`のバックエンドの機能のみがある感じですね。
LaravelをAPI化したい場合に選択されるライブラリかと思います。

https://readouble.com/laravel/9.x/ja/fortify.html

# 環境
* Laravel：9.24.0
* PHP：8.1

# 1. インストールする
```php
composer require laravel/fortify
```
`php artisan route:list`を実行するとルーティングが追加されていることが確認できます。

# 2. Fortifyで使用するファイルを作成する
設定に必要なファイルを作成します。
```php
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
```
上記のコマンドを実行するとマイグレーションファイルも作成されますので、マイグレーションを実行します。
```php
php artisan migrate
```

# 3. サービスプロバイダを登録する
`config/app.php`の`providers`にFortifyのサービスプロバイダを登録します。
```app.php
'providers' => [
    // 略
    App\Providers\FortifyServiceProvider::class, // 追加
]
```

# 4. 各認証機能のON/OFFを切り替える
`config/fortify.php`の`features`を編集すると各認証機能のON/OFFを切り替えることができます。使用しない機能はコメントアウトします。
```fortify.php
'features' => [
    Features::registration(), // ユーザー登録
    Features::resetPasswords(), // パスワードリセット
    Features::emailVerification(), // メールアドレス確認
    // Features::updateProfileInformation(), // 登録情報の更新
    // Features::updatePasswords(), // パスワード更新
    // Features::twoFactorAuthentication([ // 二要素認証
        // 'confirm' => true,
        // 'confirmPassword' => true,
        // 'window' => 0,
    // ]),
],
```
`Fortify`を`Jetstream`と組み合わせて使用しない場合は以下の3つのみ有効にすることが推奨されています。
* ユーザー登録
* パスワードリセット
* メールアドレス確認

https://laravel.com/docs/9.x/fortify#fortify-features

# 5. ビュー用のルーティングを無効化する
`Fortify`では元からビュー用のルーティングも定義されていますが、今回はバックエンドのみで使用する想定なので無効化します。
```fortify.php
'views' => false,
```

# 6. ルーティングのURLにプレフィックスを追加する
何も設定しなければルーティングのURLが`/login`のようになっていますが、`API`として使用する際は`/api/login`のようにプレフィックスをつけたいことが多いかと思います。そういった場合は下記のように`prefix`を設定します。
```fortify.php
'prefix' => 'api',
```

# 7. 各認証機能のカスタマイズ
機能を細かくカスタマイズしたい場合は`app/Actions/Fortify`にある各ファイルを修正します。
ファイルにはバリデーションや保存処理などが書かれていて、簡単にカスタマイズすることができます。

ファイル名を見ると用途が分かるかと思いますが、一応書いておきます。
* **CreateNewUser.php**
→ ユーザー登録用
* **PasswordValidationRules.php**
→ パスワードのバリデーションルールが書かれたファイルで、各クラスの中でトレイトで呼ばれています。
* **ResetUserPassword.php**
→ パスワードリセット用
* **UpdateUserPassword.php**
→ パスワード更新用
* **UpdateUserProfileInformation.php**
→ 登録情報の更新用

ちなみに上記の各クラスは`FortifyServiceProvider.php`の`boot`メソッド内で読み込まれています。
```FortifyServiceProvider.php
public function boot()
{
    Fortify::createUsersUsing(CreateNewUser::class);
    Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
    Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
    Fortify::resetUserPasswordsUsing(ResetUserPassword::class);

    RateLimiter::for('login', function (Request $request) {
        $email = (string) $request->email;

        return Limit::perMinute(5)->by($email.$request->ip());
    });

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


# 8. ルーティングのカスタマイズ
ルーティングのURLを変更したり、ミドルウェアの割り当てを外したいことがあると思います。ルーティングをカスタマイズしたい場合は一旦デフォルトのルーティングを削除して新たに`Fortify`用のルーティングを作成します。

## 8.1 ルーティングを削除
`app/Providers/FortifyServiceProvider.php`を編集します。
```FortifyServiceProvider.php
public function register()
    {
        Fortify::ignoreRoutes(); // 追加する
    }
```
上記のコードを追加すると`Fortify`のデフォルトのルーティングを全て削除できます。

## 8.2 新たにFortify用のルーティングファイルを作成する
`routes`ディレクトリ直下に`fortify.php`ファイルを作成します。

`vendor/laravel/fortify/routes/routes.php`のコードをコピーして、作成した`fority.php`に貼り付けます。

あとは`app/Providers/RouteServiceProvider.php`にルーティングを登録します。
```RouteServiceProvider.php
public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));

        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
        // fortifyのルーティングを追加する
        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/fortify.php'));
    });
}
```

# 最後に
ここまで見ていただき、ありがとうございました。
できるだけ間違いがないよう気をつけて書いていますが、何かあれば気軽にご指摘いただければと思います。


# 参考
https://readouble.com/laravel/9.x/ja/fortify.html

https://laravel.com/docs/9.x/fortify

https://www.webopixel.net/php/1661.html

https://qiita.com/ntm718/items/8452b31f13b63e516824