新人PGのLaravel備忘録～ユーザー認証時の項目追加～

# はじめに
こちらは筆者がLaravelに関する知識の定着を図るための投稿です。
以下の点にご注意ください
* この記事の読者は私と同じ実務歴半年~1年程度の新人PGの方を想定しています
* 記事内において間違いや冗長な説明が多々あることをご容赦ください
* 公式ドキュメントと相違がある場合はそちらを参考にしてください
* 公の場で記事を引用していただく場合は予めご連絡ください
* コメント大歓迎です！！出来るだけ返信しようと思っております！！
# 今回のテーマ
Laravelではユーザー認証機能を簡単に実装できるようにいくつかの無料パッケージを提供しています。今回はその中の一つであるLaravel Breezeパッケージを使用してユーザー認証を行った際にメールアドレスとパスワード以外の項目もログイン認証に用いる方法を紹介します。

:::note warn
今回はLaravel 11で実装しています。他バージョンでの実装時は[公式ドキュメント](https://laravel.com/docs/11.x/authentication#main-content)も参照してください
:::

# 想定している読者
* ユーザーの種別に応じて閲覧できるページを制限したい人
* 各ユーザーの権限を管理者が容易に管理したい人

# 使用した環境
* laravel 11.23.5
* php 8.2.12
* phpMyAdimin 5.2.1
* Laravel Breeze 2.2.0
# 大まかな流れ
今回はメールアドレスとパスワードの認証に加えて種別(kind)カラムの情報を見ることでユーザー認証を行うようにします。また、画面回りやユーザー認証の機能はLaravel Breezeインストール時の初期設定を基にして変更します。
1. マイグレーションによる認証テーブルにkindカラムの追加 
2. ログイン用のcontrollerファイルの変更
3. 実行テスト
# 1.マイグレーションによる認証テーブルの項目変更
Laravelは最初のマイグレーション時に認証用テーブルとしてusersテーブルを作成しています。このusersテーブルにkindカラムを追加します。
![変更前のusersテーブル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/5d718081-ad85-48b4-e8c8-e165ee70a108.png "変更前のusersテーブル")

<details><summary>マイグレーションファイルのコード</summary>

```terminal
php artisan make:migration add_kind_to_users_table --table=users
```


```php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddKindToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('kind')->nullable(); // kindカラムを追加
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('kind'); // kindカラムを削除
        });
    }
}

```

```terminal
php artisan migrate
```

</details>

実行後にもう一度usersテーブルを確認するとkindカラムが追加されている
![変更後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/6d8bfa13-419e-36fc-2430-05c8731eddff.png "変更後")

# 2.ログイン用のcontrollerファイルの変更
まず、どのcontrollerがログイン機能に用いられているかを"php artisan route:list"コマンドで調べます。下の画像のようにAuth\AuthenticatedSessionControllerのstore()メソッドによってログイン機能が実装されていることが分かりました。
![route:listコマンド実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/0ed90f20-34d4-d461-2a50-07e2a2989b7d.png "route:listコマンドの実行結果")
次にstore()メソッド内のコードを確認します。
![store()メソッド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/d3df172f-38d4-e4d2-6ad6-8d2ee47b0b62.png)
コードを見ると、どうやら実際の認証動作を行っているのはLoginRequestクラスのauthenticate()メソッドのようなので今度はLoginRequestクラスを確認します。
![anthenticate()メソッド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/d9c26c9a-6ca8-e494-096e-96d85f4b0af9.png)
赤線部のようにAuth::attempt()メソッドによって認証を行っているようです。[公式ドキュメント](https://laravel.com/docs/11.x/authentication#authenticating-users)によるとattemptは[key=>value]の組み合わせを要素にもつ配列を指定でき、usersテーブルのkeyのカラムにvalueの値を持つユーザーが存在するかどうかによって認証を行い、認証が成功するとtrue、そうでない場合はfalseを返すようです。ここに以下のようにkindのカラムに関する条件を書くことで追加の認証条件を付与します。
<details><summary>kindカラムの条件を追加したコード例</summary>

```php:..\app\Http\Requests\Auth\LoginRequest.php
    public function authenticate(): void
    {
        $this->ensureIsNotRateLimited();

        // kindカラムが3の時だけ認証されるように条件を追加
        $credentials = $this->only('email', 'password');
        $credentials['kind'] = 3;

        if (! Auth::attempt($credentials, $this->boolean('remember'))) {
            RateLimiter::hit($this->throttleKey());

            throw ValidationException::withMessages([
                'email' => trans('auth.failed'),
            ]);
        }

        RateLimiter::clear($this->throttleKey());
    }
```
</details>

# 3.実行テスト
最後に実行テストを行います。今回は以下のようなレコードをusersテーブルに登録してテスト行いました。
![テスト用レコード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/03a534eb-7a85-8524-1a37-824283cc0f4d.png)
## kindカラムの条件が合致している場合
最初kindカラムは3に設定してあります。
![kindが3の場合](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/4cf241a6-2e3a-bdcf-1e06-03ab97856b3c.png)

ログインすると以下のような画面が表示されます。
![ログイン成功](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/0bfa91d2-1164-a0ac-4282-4af043ccffc0.png)
## kindカラムの条件が合致しない場合
次に以下の画像のようにkindカラムを1に設定したものでログインを試みます。
![kindが1の場合](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/4378f93b-535b-1264-1a3c-4622255573dc.png)
以下の画像のように「資格情報が合致しませんでした」と表示が出ました。
![ログイン失敗](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494105/2248d82d-3c82-94e5-e269-43c9bd077d86.png)

# まとめ
ユーザー認証に追加条件を加えるには対象controllerのAuth::attemptメソッドにkeyとvalueを書き加えれば良いということがわかりました。また、テーブルの対象カラムを編集することでデータベース管理者が動的に権限を変更できることがわかりました。