環境
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を設定したルートにアクセスできるようになります。


