前のページでの作業によって,ユーザ登録とログイン機能が実現できました.しかしながらユーザ登録に利用されたメールアドレスが正しいアドレスで受信可能なアドレスであるかどうかの検証はできていません.ここでは,ユーザ登録と同時に登録メールアドレスにメールを送信し,メールに含まれたリンクをクリックして初めてシステムを利用できるようにします.作業を開始する前に,メール送信の設定が完了し,メールの送信ができることを確認しておいてください.
まずモデルを修正して,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 に受信可能なメールアドレスを指定してください.
上の画面で「REGISTER」を押すと下の画面に移行するはずです.この時,メールの送信に若干の時間を要すので,画面の遷移まで時間がかかるようになります.(慌てて「REGISTER」を連打しないように気をつけてください.)
送信されているはずのメールを受信します.メール本文にある「Verify Email Address」ボタンをクリックするか,メール本文に記載されている URL のリンクをクリックします.
その結果,メールアドレスが検証されてログインできました.
一方でまだメールアドレスの検証が終わっていない user_a でログインを試みます.
ログイン自体はできましたが,メールの検証を促すページにリダイレクトされました.なお,テストユーザのメールアドレスは出鱈目なものですから,「RESEND VERIFICATION EMAIL」ボタンを押してもメールの送信の結果はエラーメールになることが明らかです.次のページでシーダを修正して3名のテストユーザもログインできるようにします.