0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravel(v12x)での二段階認証(2FA) ブラッシュアップ

Posted at

はじめに

この記事は私が以前投稿した記事の続きとなっております。
ご覧になる前に、ぜひそちらの記事からご覧ください。
Laravel(v12x)での二段階認証(2FA)実装方法について


前回の投稿でLaravel Breeze環境構築下でのログイン時の2FAを実装しましたが、開発を進めていくうちに私はあることに気づきました...

「このままやとサインアップするときに詰むんじゃね?」

そう。何を隠そう前回の記事では新規ユーザー登録時のPINコード生成・送信機能を実装しておらず、又、PINコードの再送機能も無し、加えてログイン後のコンテンツには2FAミドルウェアを効かせていました。

これにより、新規登録時は2FAを通過できないという地獄みたいな実装となっておりました。

そこで今回の記事内容については以下のようになっております。

  • 新規登録時のPINコード生成・送信機能 実装方法
  • PINコード検証画面でのPINコード再送機能 実装方法

初学者がグダった末に生まれた備忘録投稿ですが、温かい目で読んでいただけると幸いです。

前提条件

  • Laravel Sail (v12x)
  • Breezeでのユーザー認証実装済み
  • 前回の記事に習って2FA機能(不完全)を実装済み

新規登録時のPINコード生成・送信機能 実装方法

いたってシンプルです。
新規登録時に呼び出されるコントローラーのメソッドに、前回作成したgenerateTwoFactorCodeメソッド(PINコード生成>DB保存>メール送信を行う機能)を追加することで実装できます。

app/Http/Controllers/Auth/RegenerateUserController.php
// 省略
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にリダイレクトされる仕様ですが、ここを書き換えて以下のようにします。

app/Http/Controllers/Auth/RegenerateUserController.php
// 省略
        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.phpregenerateメソッドが実行される処理が出来ました。

  • PINコード再送処理を行うregenerateメソッド作成
    TwoFactorController.phpregenerateメソッドを作成し、処理を書き込みます。

    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');
    }
    
    // 省略
    

    処理内容としては、

    1. $userにメールアドレス・パスワード認証済みのユーザー情報を格納
    2. 最初に生成したPINコード、有効期限を削除
    3. generateTwoFactorCodeメソッドを実行し、PINコード、有効期限を生成しメール送信
    4. verify-pinルートを呼び出し、PINコード検証画面にリダイレクト

    これにより、検証画面のPINコード再送ボタン>ルート呼び出し>PINコード再送処理を実行の流れが実装できました。

まとめ

以上の実装により、PINコードによる二段階認証(2FA)は今度こそ完了です。
今回の機能修正を通して、機能実装はあらゆるユースケースを考慮したり、モデルを参考にすることが重要だと感じました。
最後まで読んでいただきありがとうございました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?