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 によるユーザ認証

メールアドレスの検証

前のページでの作業によって,ユーザ登録とログイン機能が実現できました.しかしながらユーザ登録に利用されたメールアドレスが正しいアドレスで受信可能なアドレスであるかどうかの検証はできていません.ここでは,ユーザ登録と同時に登録メールアドレスにメールを送信し,メールに含まれたリンクをクリックして初めてシステムを利用できるようにします.作業を開始する前に,メール送信の設定が完了し,メールの送信ができることを確認しておいてください.

まずモデルを修正して,User モデルでメールの検証を必須にします.具体的には,User モデルが Authenticatable を継承 (extends) します(これは変更なし)が,MustVerifyEmail のインタフェースを実行する (implements) ようにします.

app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'student_id',
        'login_id',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];
}

マイグレーションファイルには email_verified_at 属性がすでに定義されていることを確認します(変更点はありません).この email_verified_at が NULL の場合にはログインが許可されず,日時が格納されているユーザのログインだけが許可されるようにこれから設定します.

database/migrations/2014_10_12_000000_create_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::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};

メール検証のためのルートを定義します.

routes/auth.php
<?php

use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Auth\NewPasswordController;
use App\Http\Controllers\Auth\PasswordController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\Auth\RegisteredUserController;
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;

use Illuminate\Foundation\Auth\EmailVerificationRequest;
use Illuminate\Http\Request;

Route::middleware('guest')->group(function () {
    Route::get('register', [RegisteredUserController::class, 'create'])
                ->name('register');

    Route::post('register', [RegisteredUserController::class, 'store']);

    Route::get('login', [AuthenticatedSessionController::class, 'create'])
                ->name('login');

    Route::post('login', [AuthenticatedSessionController::class, 'store']);

    Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
                ->name('password.request');

    Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
                ->name('password.email');

    Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
                ->name('password.reset');

    Route::post('reset-password', [NewPasswordController::class, 'store'])
                ->name('password.store');
});

Route::middleware('auth')->group(function () {
    Route::get('verify-email', EmailVerificationPromptController::class)
                ->name('verification.notice');

    Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
                ->middleware(['signed', 'throttle:6,1'])
                ->name('verification.verify');

    Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
                ->middleware('throttle:6,1')
                ->name('verification.send');

    Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
                ->name('password.confirm');

    Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);

    Route::put('password', [PasswordController::class, 'update'])->name('password.update');

    Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
                ->name('logout');
});

Route::get('/email/verify', function () {
    return view('auth.verify-email');
})->middleware('auth')->name('verification.notice');

Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
    $request->fulfill();
    return redirect('/dashboard');
})->middleware(['auth', 'signed'])->name('verification.verify');

Route::post('/email/verification-notification', function (Request $request) {
    $request->user()->sendEmailVerificationNotification();
    return back()->with('message', 'Verification link sent!');
})->middleware(['auth', 'throttle:6,1'])->name('verification.send');

データベースを一旦リセットします.

vagrant@ubuntu2204 laravelAuth $ php artisan migrate:rollback; php artisan migrate; php artisan db:seed ⏎

   INFO  Rolling back migrations.

  2023_11_03_101930_add_login_id_to_users_table ............ 1ms DONE
  2019_12_14_000001_create_personal_access_tokens_table .... 6ms 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 ..................... 6ms DONE


   INFO  Running migrations.

  2014_10_12_000000_create_users_table ..................... 9ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ..... 4ms DONE
  2019_08_19_000000_create_failed_jobs_table ............... 7ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ... 12ms DONE
  2023_11_03_101930_add_login_id_to_users_table ........... 13ms DONE


   INFO  Seeding database.

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

vagrant@ubuntu2204 laravelAuth $

ユーザ登録の実験を行います.メール検証を行うのでここからは E-mail に受信可能なメールアドレスを指定してください.

laravel10-2023-auth-20.png

上の画面で「REGISTER」を押すと下の画面に移行するはずです.この時,メールの送信に若干の時間を要すので,画面の遷移まで時間がかかるようになります.(慌てて「REGISTER」を連打しないように気をつけてください.)

laravel10-2023-auth-21.png

送信されているはずのメールを受信します.メール本文にある「Verify Email Address」ボタンをクリックするか,メール本文に記載されている URL のリンクをクリックします.

laravel10-2023-auth-22.png

その結果,メールアドレスが検証されてログインできました.

laravel10-2023-auth-23.png

一方でまだメールアドレスの検証が終わっていない user_a でログインを試みます.

laravel10-2023-auth-24.png

ログイン自体はできましたが,メールの検証を促すページにリダイレクトされました.なお,テストユーザのメールアドレスは出鱈目なものですから,「RESEND VERIFICATION EMAIL」ボタンを押してもメールの送信の結果はエラーメールになることが明らかです.次のページでシーダを修正して3名のテストユーザもログインできるようにします.

laravel10-2023-auth-25.png

目次に戻る