環境
PHP 8.1
Laravel 9.19
初めに
手早く実装場合はJetstreamとかBreezeを使用するといいと思います。
laravel / breezeこの記事では使用しませんがBreezeを参考に進めていきます。
モデル
Laravelの初期設定はUserモデルが認証で使用するモデルになるので、今回はこれをそのまま使用します。
初期状態ではMustVerifyEmail
がコメントアウトしていると思うので、コメントを外して実装します。
Models/User.php
use Illuminate\Contracts\Auth\MustVerifyEmail; class User extends Authenticatable implements MustVerifyEmail {
確認メール用コントローラーの作成
新しいコントローラーを作成して、ざっくりと枠組みを作ってみましょう。
全部で3つのアクションメソッドを作ります。
index | 確認メールの送信ボタンを表示する画面 |
---|---|
notification | メールを送信するアクション |
verification | 送信したメールアドレスに記載するリンクのアクション |
Http/Controllers/Auth/EmailVerificationController.php
<?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
はそのまま使うのがいいのではないかと思います。
routes/web.php
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
に日付が入るので、ここの処理ではメール確認している場合はホーム画面にリダイレクトして、未確認の場合はビューを表示するということをしています。
Http/Controllers/Auth/EmailVerificationController.php
/** * 確認メール送信画面 * * @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
はメール送信後に設定します。
メール送信前に表示して、送信後にセッションを入れてまたこの画面に戻る流れです。
resources/views/auth/verify-email.blade.php
<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
を実行しています。
こいつを実行することでメールが送信されるようです。
Http/Controllers/Auth/EmailVerificationController.php
/** * 確認メール送信 * * @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
に下記を追記します。
Providers/AuthServiceProvider.php
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で指定した場所にメールテンプレートを作りします。
resources/views/emails/verify-email.blade.php
リンクをクリックしてください!!<br> <a href="{{ $displayableActionUrl }}">{{ $actionUrl }}</a>
メールのURLから飛んだ先のアクション
最後にメールのリンクから飛んできた先のアクションを作成します。
EmailVerificationController
のverification
ですね。
ここもメール送信と同じく、MustVerifyEmail
のmarkEmailAsVerified
を実行しています。
email_verified_at
カラムに現在日時を入れてアップデートしているだけですね。
正常に完了した場合はホームへリダイレクトさせます。
URL(Hash)のチェックとかはルートで設定したsignedミドルウェアでやってくれます。
Http/Controllers/Auth/EmailVerificationController.php
/** * メールリンクの検証 * * @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
を設定したルートにアクセスできるようになります。