はじめに
この記事は私が以前投稿した記事の続きとなっております。
ご覧になる前に、ぜひそちらの記事からご覧ください。
Laravel(v12x)での二段階認証(2FA)実装方法について
前回の投稿でLaravel Breeze環境構築下でのログイン時の2FAを実装しましたが、開発を進めていくうちに私はあることに気づきました...
「このままやとサインアップするときに詰むんじゃね?」
そう。何を隠そう前回の記事では新規ユーザー登録時のPINコード生成・送信機能を実装しておらず、又、PINコードの再送機能も無し、加えてログイン後のコンテンツには2FAミドルウェアを効かせていました。
これにより、新規登録時は2FAを通過できないという地獄みたいな実装となっておりました。
そこで今回の記事内容については以下のようになっております。
- 新規登録時のPINコード生成・送信機能 実装方法
- PINコード検証画面でのPINコード再送機能 実装方法
初学者がグダった末に生まれた備忘録投稿ですが、温かい目で読んでいただけると幸いです。
前提条件
- Laravel Sail (v12x)
- Breezeでのユーザー認証実装済み
- 前回の記事に習って2FA機能(不完全)を実装済み
新規登録時のPINコード生成・送信機能 実装方法
いたってシンプルです。
新規登録時に呼び出されるコントローラーのメソッドに、前回作成したgenerateTwoFactorCodeメソッド(PINコード生成>DB保存>メール送信を行う機能)を追加することで実装できます。
// 省略
public function store(Request $request): RedirectResponse
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:' . User::class],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
event(new Registered($user));
Auth::login($user);
// 以下のコードを変更する
return redirect(route('dashboard', absolute: false));
}
// 省略
上記の下から3行目のreturn redirect(route('dashboard', absolute: false));をご覧ください。
現状、新規登録したユーザーはdashboardにリダイレクトされる仕様ですが、ここを書き換えて以下のようにします。
// 省略
event(new Registered($user));
Auth::login($user);
// 以下が変更後のコード
$user->generateTwoFactorCode();
return redirect()->route('verify.pin');
}
// 省略
こうすることにより、ログイン後のユーザーに対してgenerateTwoFactorCodeを実行しPINコード生成、DB保存、メール送信後にPINコード検証画面へリダイレクトします。
これにより新規登録ユーザーに対しても2FAを実装することが出来ます。
PINコード再送機能 実装方法
-
PINコード検証画面にPINコード再送用の要素を追加
/resources/views/auth/verify-pin.blade.phpにPINコード再送用のrouteを呼び出すトリガーとなる要素を追記します。/resources/views/auth/verify-pin.blade.php<x-guest-layout> <form method="POST" action="{{ route('verify.pin.store') }}"> @csrf <div class="text-center mt-4"> <x-input-label for="two_factor_code" value="認証コード" /> <x-text-input id="two_factor_code" type="text" name="two_factor_code" required autofocus /> @error('two_factor_code') <div> <span class="text-red-600 text-sm">{{ $message }}</span> </div> @enderror </div> <div class="text-center mt-4"> <x-primary-button>認証する</x-primary-button> </div> </form> <!-- 以下のformを追記 --> <form method="POST" action="{{ route('verify.pin.regenerate') }}" class=" text-center"> @csrf <button type="submit" class="text-blue-600 text-sm underline bg-transparent border-none mt-5"> PINコードを再送信する </button> </form> </x-guest-layout>上記のようにformを追記し、
route('verify.pin.regenerate')でルートを設定します。
これにより、form内のbuttonが押されることによりPINコード再送用のrouteを呼び出すことが出来ます。
-
PINコード再送処理を呼び出すRouteを設定
/routes/web.phpを開くと、現状以下のようなメールアドレス・パスワード認証済み(2FA認証前)のミドルウェアが適用されたグループがあるかと思います。/routes/web.php// 省略 Route::middleware('auth')->group(function () { Route::get('/verify-pin', [TwoFactorController::class, 'show'])->name('verify.pin'); Route::post('/verify-pin', [TwoFactorController::class, 'verify'])->name('verify.pin.store'); }); // 省略ここにPINコード再送処理を呼び出すルートを設定します。
php/routes/web.php// 省略 Route::middleware('auth')->group(function () { Route::get('/verify-pin', [TwoFactorController::class, 'show'])->name('verify.pin'); Route::post('/verify-pin', [TwoFactorController::class, 'verify'])->name('verify.pin.store'); // 以下のルートを追記 Route::post('/verify-pin/regenerate', [TwoFactorController::class, 'regenerate'])->name('verify.pin.regenerate'); }); // 省略これにより先ほどのformのボタンによって、このルートが呼び出され
TwoFactorController.phpのregenerateメソッドが実行される処理が出来ました。
-
PINコード再送処理を行うregenerateメソッド作成
TwoFactorController.phpにregenerateメソッドを作成し、処理を書き込みます。app/Http/Controllers/TwoFactorController.php// 省略 public function regenerate() { $user = Auth::user(); $user->two_factor_code = null; $user->two_factor_expires_at = null; $user->save(); $user->generateTwoFactorCode(); return redirect()->route('verify.pin'); } // 省略処理内容としては、
-
$userにメールアドレス・パスワード認証済みのユーザー情報を格納 - 最初に生成したPINコード、有効期限を削除
-
generateTwoFactorCodeメソッドを実行し、PINコード、有効期限を生成しメール送信 -
verify-pinルートを呼び出し、PINコード検証画面にリダイレクト
これにより、検証画面のPINコード再送ボタン>ルート呼び出し>PINコード再送処理を実行の流れが実装できました。
-
まとめ
以上の実装により、PINコードによる二段階認証(2FA)は今度こそ完了です。
今回の機能修正を通して、機能実装はあらゆるユースケースを考慮したり、モデルを参考にすることが重要だと感じました。
最後まで読んでいただきありがとうございました!