環境
PHP 8.1
Laravel 9.19
初めに
手早く実装場合はJetstreamとかBreezeを使用するといいと思います。
この記事では使用しませんがBreezeを参考に進めていきます。
モデル
Laravelの初期設定はUserモデルが認証で使用するモデルになるので、今回はこれをそのまま使用します。
初期状態ではMustVerifyEmailがコメントアウトしていると思うので、コメントを外して実装します。
use Illuminate\Contracts\Auth\MustVerifyEmail;
class User extends Authenticatable implements MustVerifyEmail{確認メール用コントローラーの作成
新しいコントローラーを作成して、ざっくりと枠組みを作ってみましょう。
全部で3つのアクションメソッドを作ります。
| index | 確認メールの送信ボタンを表示する画面 |
|---|---|
| notification | メールを送信するアクション |
| verification | 送信したメールアドレスに記載するリンクのアクション |
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;use App\Models\User;use App\Providers\RouteServiceProvider;use Illuminate\Auth\Events\Verified;use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request;use Illuminate\View\View;
class EmailVerificationController extends Controller{ /** * 確認メール送信画面 */ public function index() {}
/** * 確認メール送信 */ public function notification() {}
/** * メールリンクの検証 */ public function verification() {}}ルートの設定
ルートの設定をします。
ミドルウェアにアクセス回数制限をするthrottleと期限付きURLを指定するsignedを設定してます。
URLは自由に変更できますが、nameはそのまま使うのがいいのではないかと思います。
use App\Http\Controllers\Auth\EmailVerificationController;
Route::controller(EmailVerificationController::class) ->prefix('email')->name('verification.')->group(function () { // 確認メール送信画面 Route::get('verify', 'index')->name('notice'); // 確認メール送信 Route::post('verification-notification', 'notification') ->middleware('throttle:6,1')->name('send'); // 確認メールリンクの検証 Route::get('verification/{id}/{hash}', 'verification') ->middleware(['signed', 'throttle:6,1'])->name('verify'); });あとはメールの確認が必要なルートにverifiedを適用します。
Route::middleware(['web', 'verified', 'auth'])これで設定したルートにアクセスした際メール確認をしていない場合は、「確認メール送信画面」にリダイレクトされます。
確認メール送信画面
メールの送信ボタンを配置する画面を作ります。
EmailVerificationControllerのindexですね。
hasVerifiedEmailはemail_verified_atカラムがnullでなかったらtrueを返します。
最終的にメール確認をするとこのemail_verified_atに日付が入るので、ここの処理ではメール確認している場合はホーム画面にリダイレクトして、未確認の場合はビューを表示するということをしています。
/** * 確認メール送信画面 * * @param Request $request * @return RedirectResponse|View*/public function index(Request $request): RedirectResponse|View{ return $request->user()->hasVerifiedEmail() ? redirect()->intended(RouteServiceProvider::HOME) : view('auth.verify-email');}表示するビューを作成します。
セッションのverification-link-sentはメール送信後に設定します。
メール送信前に表示して、送信後にセッションを入れてまたこの画面に戻る流れです。
<div> <h1><a href="/">確認メールの送信</a></h1> <div> @if (session('status') === 'verification-link-sent') <p> 登録したメールアドレスを確認してください!! </p> <p ><a href="/">TOPに戻る</a></p> @else <p> 確認メールを送信してください!! </p> <form method="post" action="{{ route('verification.send') }}"> @method('post') @csrf <div> <button type="submit">確認メールを送信</button> </div> </form> @endif </div></div>これでルートに設定した、確認メールが必要な画面にアクセスするとこの画面に遷移します。
確認メール送信アクション
確認メール送信機能を作ります。
EmailVerificationControllerのnotificationですね。
ここではユーザーモデルの親クラスでトレイトしているMustVerifyEmailのsendEmailVerificationNotificationを実行しています。
こいつを実行することでメールが送信されるようです。
/** * 確認メール送信 * * @param Request $request * @return RedirectResponse */public function notification(Request $request): RedirectResponse{ /** @var User $user */ $user = $request->user();
// メール確認済みの場合はトップへ if ($user->hasVerifiedEmail()) { return redirect()->intended(RouteServiceProvider::HOME); }
// メール送信 $user->sendEmailVerificationNotification();
return back()->with('status', 'verification-link-sent');}これで確認メールを送信できますが、今の状態だとメールのテンプレートがLaravelデフォルトのものなので使いにくいと思います。
カスタマイズするにはAuthServiceProvider.phpを次のbootに下記を追記します。
use Illuminate\Auth\Notifications\VerifyEmail;
// ...
public function boot(){ $this->registerPolicies();
//
VerifyEmail::toMailUsing(function ($notifiable, $url) { return (new MailMessage) ->subject('メールアドレスの確認') ->action('確認', $url) ->view('emails.verify-email'); });}viewで指定した場所にメールテンプレートを作りします。
リンクをクリックしてください!!<br><a href="{{ $displayableActionUrl }}">{{ $actionUrl }}</a>メールのURLから飛んだ先のアクション
最後にメールのリンクから飛んできた先のアクションを作成します。
EmailVerificationControllerのverificationですね。
ここもメール送信と同じく、MustVerifyEmailのmarkEmailAsVerifiedを実行しています。
email_verified_atカラムに現在日時を入れてアップデートしているだけですね。
正常に完了した場合はホームへリダイレクトさせます。
URL(Hash)のチェックとかはルートで設定したsignedミドルウェアでやってくれます。
/** * メールリンクの検証 * * @param Request $request * @return RedirectResponse */public function verification(Request $request): RedirectResponse{ /** @var User $user */ $user = $request->user();
if ($user->hasVerifiedEmail()) { return redirect()->intended(RouteServiceProvider::HOME.'?verified=1'); }
// email_verified_atカラムの更新 if ($user->markEmailAsVerified()) { event(new Verified($user)); }
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');}email_verified_atに日付が入力されるとverifiedを設定したルートにアクセスできるようになります。

