Laravel 10 入門トップページ


目次

  1. 全体の概要
  2. Laravel によるユーザ認証
    1. 概要
    2. プロジェクトの作成と初期設定
    3. メールの設定
    4. Laravel Breeze のインストール
    5. ユーザ登録機能の動作確認
    6. シーダによるテストユーザの登録
    7. テーブルにログイン ID の属性を追加
    8. ユーザ登録機能の修正
    9. ログイン ID でログインするように変更
    10. メールアドレスの検証
    11. シーダの修正
    12. 検証メールの有効期限と再送信
    13. セッション継続時間の確認と変更
    14. メールアドレスの変更
    15. パスワードの変更
    16. アカウントの削除
  3. ユーザ認証を備えたコメント掲示板の開発
  4. マルチ認証の実現

Laravel でユーザ認証とマルチ認証を実現する

Laravel によるユーザ認証

テーブルにログイン ID の属性を追加

前のページまでの作業で,メールアドレスとパスワードでログインができるようになりました.ここではメールアドレスの代わりにログイン ID でログインできるようにするためにデータベースのテーブルにログイン ID (とついでに学籍番号も)の属性(列)を追加します.

まず,users テーブルに login_id 列を追加する必要があります.まだ開発段階であるので,すでにあるマイグレーションファイルを修正して,ロールバックとマイグレーションを実行しても構いません.一方ですでに本番環境で運用段階にある場合は,ロールバックしてデータを削除することはできません.今回はすでにあるテーブルに列を追加するために新たなマイグレーションファイルを生成することにします.

vagrant@ubuntu2204 laravelAuth $ php artisan make:migration add_login_id_to_users_table --table=users ⏎

   INFO  Migration [database/migrations/2023_11_03_101930_add_login_id_to_users_table.php] created successfully.

vagrant@ubuntu2204 laravelAuth $

上のコマンドで次のようなファイルが生成されました.

database/migrations/yyyy_mm_dd_hhmmss_add_login_id_to_users_table.php<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }
};

これを次のように修正して,ログイン ID と学籍番号の属性を追加するようにします.なお,すでにデータが投入されていることを前提にどちらの属性も NULL 値を許可し,一意性制約は設定していません(が後で変更します).すでに users テーブルにレコードがある状況で,一意性制約を持ち NULL 値を許可しない属性(列)を追加することができないのは直感的にも理解できることだと思います.またロールバックしたときに追加した属性が削除されるようにもしています.

database/migrations/yyyy_mm_dd_hhmmss_add_login_id_to_users_table.php<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->integer('student_id')->nullable();
            $table->string('login_id')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('student_id');
            $table->dropColumn('login_id');
        });
    }
};

マイグレーションの状況を確認しながら,(1) マイグレーションを実行して列を追加します.その後,(2) ロールバックを一度実行して列が削除されることを確認します.(3) もう一度ロールバックを実行すると全てのテーブルが削除されます.その後,(4) マイグレーションを実行すると列の追加まで一気に実行されます.以降はロールバックで一気に全てのテーブルが削除されるようになります.

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎

  Migration name ...................................... Batch / Status
  2014_10_12_000000_create_users_table ....................... [1] Ran
  2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran
  2019_08_19_000000_create_failed_jobs_table ................. [1] Ran
  2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran
  2023_11_03_101930_add_login_id_to_users_table .............. Pending

vagrant@ubuntu2204 laravelAuth $ php artisan migrate ⏎ # (1) 

   INFO  Running migrations.

  2023_11_03_101930_add_login_id_to_users_table ............ 17ms DONE

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎

  Migration name ...................................... Batch / Status
  2014_10_12_000000_create_users_table ....................... [1] Ran
  2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran
  2019_08_19_000000_create_failed_jobs_table ................. [1] Ran
  2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran
  2023_11_03_101930_add_login_id_to_users_table .............. [2] Ran

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback ⏎ # (2) 

   INFO  Rolling back migrations.

  2023_11_03_101930_add_login_id_to_users_table ............ 17ms DONE

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎

  Migration name ...................................... Batch / Status
  2014_10_12_000000_create_users_table ....................... [1] Ran
  2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran
  2019_08_19_000000_create_failed_jobs_table ................. [1] Ran
  2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran
  2023_11_03_101930_add_login_id_to_users_table .............. Pending

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback ⏎ # (3) 

   INFO  Rolling back migrations.

  2019_12_14_000001_create_personal_access_tokens_table .... 14ms DONE
  2019_08_19_000000_create_failed_jobs_table ................ 5ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ...... 5ms DONE
  2014_10_12_000000_create_users_table ...................... 5ms DONE

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎

  Migration name ...................................... Batch / Status
  2014_10_12_000000_create_users_table ....................... Pending
  2014_10_12_100000_create_password_reset_tokens_table ....... Pending
  2019_08_19_000000_create_failed_jobs_table ................. Pending
  2019_12_14_000001_create_personal_access_tokens_table ...... Pending
  2023_11_03_101930_add_login_id_to_users_table .............. Pending

vagrant@ubuntu2204 laravelAuth $ php artisan migrate ⏎ # (4) 

   INFO  Running migrations.

  2014_10_12_000000_create_users_table ..................... 15ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ...... 4ms DONE
  2019_08_19_000000_create_failed_jobs_table ................ 9ms DONE
  2019_12_14_000001_create_personal_access_tokens_table .... 11ms DONE
  2023_11_03_101930_add_login_id_to_users_table ............. 7ms DONE

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎

  Migration name ...................................... Batch / Status
  2014_10_12_000000_create_users_table ....................... [1] Ran
  2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran
  2019_08_19_000000_create_failed_jobs_table ................. [1] Ran
  2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran
  2023_11_03_101930_add_login_id_to_users_table .............. [1] Ran

vagrant@ubuntu2204 laravelAuth $

上の作業の途中で随時テーブルの状況を確認すると次のようになります.

sqlite> .headers on ⏎
sqlite> .schema users ⏎ # (1) の実行前

CREATE TABLE IF NOT EXISTS "users" (
    "id" integer primary key autoincrement not null,
    "name" varchar not null,
    "email" varchar not null,
    "email_verified_at" datetime,
    "password" varchar not null,
    "remember_token" varchar,
    "created_at" datetime,
    "updated_at" datetime
    );
CREATE UNIQUE INDEX "users_email_unique" on "users" ("email");
sqlite> select * from users; ⏎
id|name|email|email_verified_at|password|remember_token|created_at|updated_at
1|A. Sample|a@sample.com||$2y$12$6lGSvqPP.xDa29J8XCyXJumXxgvYqJ6TipAuYAm/c3tR5lBRATYWe||2023-11-03 00:01:01|2023-11-03 00:01:01
2|B. Sample|b@sample.com||$2y$12$JbIKOUm2EpukDomlQP5WYuQF86551LUPPSCfTUJIej3j3LNKSfLpy||2023-11-03 00:02:01|2023-11-03 00:02:01
3|C. Sample|c@sample.com||$2y$12$TaYyDjyCoo1jwJOGGd0cwunI4aQgX/ti9DLdkcAYdFwzfdHUAzK/6||2023-11-03 00:03:01|2023-11-03 00:03:01
sqlite>
sqlite>
sqlite>
sqlite>
sqlite> .schema users ⏎ # (1) の実行後で,(2) の実行前
CREATE TABLE IF NOT EXISTS "users" (
    "id" integer primary key autoincrement not null,
    "name" varchar not null,
    "email" varchar not null,
    "email_verified_at" datetime,
    "password" varchar not null,
    "remember_token" varchar,
    "created_at" datetime,
    "updated_at" datetime,
    "login_id" varchar,
    "student_id" integer
    );
CREATE UNIQUE INDEX "users_email_unique" on "users" ("email");
sqlite> select * from users; ⏎
id|name|email|email_verified_at|password|remember_token|created_at|updated_at|login_id|student_id
1|A. Sample|a@sample.com||$2y$12$6lGSvqPP.xDa29J8XCyXJumXxgvYqJ6TipAuYAm/c3tR5lBRATYWe||2023-11-03 00:01:01|2023-11-03 00:01:01||
2|B. Sample|b@sample.com||$2y$12$JbIKOUm2EpukDomlQP5WYuQF86551LUPPSCfTUJIej3j3LNKSfLpy||2023-11-03 00:02:01|2023-11-03 00:02:01||
3|C. Sample|c@sample.com||$2y$12$TaYyDjyCoo1jwJOGGd0cwunI4aQgX/ti9DLdkcAYdFwzfdHUAzK/6||2023-11-03 00:03:01|2023-11-03 00:03:01||
sqlite>
sqlite>
sqlite>
sqlite> .schema users ⏎ # (2) の実行後
CREATE TABLE IF NOT EXISTS "users" (
    "id" integer primary key autoincrement not null,
    "name" varchar not null,
    "email" varchar not null,
    "email_verified_at" datetime,
    "password" varchar not null,
    "remember_token" varchar,
    "created_at" datetime,
    "updated_at" datetime
    );
CREATE UNIQUE INDEX "users_email_unique" on "users" ("email");
sqlite> select * from users; ⏎
id|name|email|email_verified_at|password|remember_token|created_at|updated_at
1|A. Sample|a@sample.com||$2y$12$6lGSvqPP.xDa29J8XCyXJumXxgvYqJ6TipAuYAm/c3tR5lBRATYWe||2023-11-03 00:01:01|2023-11-03 00:01:01
2|B. Sample|b@sample.com||$2y$12$JbIKOUm2EpukDomlQP5WYuQF86551LUPPSCfTUJIej3j3LNKSfLpy||2023-11-03 00:02:01|2023-11-03 00:02:01
3|C. Sample|c@sample.com||$2y$12$TaYyDjyCoo1jwJOGGd0cwunI4aQgX/ti9DLdkcAYdFwzfdHUAzK/6||2023-11-03 00:03:01|2023-11-03 00:03:01
sqlite>

上の SQLite の実行結果を確認すると,(1) の実行後に login_idstudent_id の属性(列)が追加されていることがわかります.しかしながら,これらの属性には UNIQUE 制約(一意性制約)が設定されていないことも分かります.ログイン ID や学籍番号は他の学生と重複した値を持つことが許されないことから UNIQUE 制約を追加しなければなりません.

実際のところまだ本番環境には移行していないので,データベースのテーブルを完全にロールバックしても問題はありません.したがって,マイグレーションファイルを次のように修正して,UNIQUE 制約を追加して,さらに NULL 値も許可しないようにします.また,このマイグレーションだけをロールバックする必要性も今後ないことから down の定義は削除しています.

database/migrations/yyyy_mm_dd_hhmmss_add_login_id_to_users_table.php<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('login_id')->unique();
            $table->integer('student_id')->unique();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }
};

この状態でロールバックとマイグレーションを実行します.

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:status ⏎

  Migration name ...................................... Batch / Status
  2014_10_12_000000_create_users_table ....................... [1] Ran
  2014_10_12_100000_create_password_reset_tokens_table ....... [1] Ran
  2019_08_19_000000_create_failed_jobs_table ................. [1] Ran
  2019_12_14_000001_create_personal_access_tokens_table ...... [1] Ran
  2023_11_03_101930_add_login_id_to_users_table .............. [1] Ran

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback ⏎

   INFO  Rolling back migrations.

  2023_11_03_101930_add_login_id_to_users_table ............ 15ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ..... 5ms DONE
  2019_08_19_000000_create_failed_jobs_table ................ 5ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ...... 6ms DONE
  2014_10_12_000000_create_users_table ...................... 5ms DONE

vagrant@ubuntu2204 laravelAuth $ php artisan migrate ⏎

   INFO  Running migrations.

  2014_10_12_000000_create_users_table ..................... 14ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ...... 4ms DONE
  2019_08_19_000000_create_failed_jobs_table ................ 8ms DONE
  2019_12_14_000001_create_personal_access_tokens_table .... 13ms DONE
  2023_11_03_101930_add_login_id_to_users_table ............ 16ms DONE

vagrant@ubuntu2204 laravelAuth $

すると login_idstudent_id 属性に NOT NULL 制約と一意性制約が設定されてことも分かります.

sqlite> .schema users ⏎
CREATE TABLE IF NOT EXISTS "users" (
    "id" integer primary key autoincrement not null,
    "name" varchar not null,
    "email" varchar not null,
    "email_verified_at" datetime,
    "password" varchar not null,
    "remember_token" varchar,
    "created_at" datetime,
    "updated_at" datetime,
    "login_id" varchar not null,
    "student_id" integer not null);
CREATE UNIQUE INDEX "users_email_unique" on "users" ("email");
CREATE UNIQUE INDEX "users_login_id_unique" on "users" ("login_id");
CREATE UNIQUE INDEX "users_student_id_unique" on "users" ("student_id");
sqlite>

テーブル定義の修正を終えたので,次はシーダを修正します.

database/seeders/UsersTableSeeder.php<?php

namespace Database\Seeders;

use Illuminate\Support\Facades\DB;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

use App\Models\User;
use Carbon\Carbon;

class UsersTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
        DB::table('users')->delete();

        User::create([
            'name' => 'A. Sample',
            'email' => 'a@sample.com',
            'login_id' => 'user_a',
            'student_id' => 6300997,
            'password' => bcrypt('abc'),
            'created_at' => '2023-11-03 00:01:01',
            'updated_at' => '2023-11-03 00:01:01'
        ]);

        User::create([
            'name' => 'B. Sample',
            'email' => 'b@sample.com',
            'login_id' => 'user_b',
            'student_id' => 6300998,
            'password' => bcrypt('abc'),
            'created_at' => '2023-11-03 00:02:01',
            'updated_at' => '2023-11-03 00:02:01'
        ]);

        User::create([
            'name' => 'C. Sample',
            'email' => 'c@sample.com',
            'login_id' => 'user_c',
            'student_id' => 6300999,
            'password' => bcrypt('abc'),
            'created_at' => '2023-11-03 00:03:01',
            'updated_at' => '2023-11-03 00:03:01'
        ]);
    }
}

データベースはロールバックのあとマイグレーションが実行された状態のはずですので,そのままデータを投入します.

vagrant@ubuntu2204 laravelAuth $ php artisan db:seed ⏎

   INFO  Seeding database.

  Database\Seeders\UsersTableSeeder .......................... RUNNING
  Database\Seeders\UsersTableSeeder ................... 658.81 ms DONE

vagrant@ubuntu2204 laravelAuth $

SQLite で投入されたデータを確認します.

sqlite> select * from users; ⏎
id|name|email|email_verified_at|password|remember_token|created_at|updated_at|login_id|student_id
1|A. Sample|a@sample.com||$2y$12$xKLWZJSJqxcu8bLNA/o2X.CvZlDWsi0t3tIVVzcFS7RzELoVQWhzC||2023-11-03 00:01:01|2023-11-03 00:01:01|user_a|6300997
2|B. Sample|b@sample.com||$2y$12$RjXhibG00aYYv8pvZ2.5MOHvdsvDlfxtdWdyoz3zUx0074MHLbBQS||2023-11-03 00:02:01|2023-11-03 00:02:01|user_b|6300998
3|C. Sample|c@sample.com||$2y$12$LGBYC5Pi5eezXPbSLVAutuNWpd8u7M/T4lVaUC3vGpp6qqF3Y65Hi||2023-11-03 00:03:01|2023-11-03 00:03:01|user_c|6300999
sqlite>

目次に戻る