Laravelに入門したい!(Laravel APIサーバー+React SPA)vol.3

前回:Laravelに入門したい!(Laravel APIサーバー+React SPA)vol.2

今回はソースコードを確認しつつ、仕様を変更していく。

API [POST /forgot-password] で、ユーザーが見つからない場合にも正常完了させる

現状、/forgot-passwordあてにメールアドレスを送信したとき、登録されているメールアドレスの場合、正常応答。登録されていない場合、異常応答する。
これでは、送信したメールアドレスのユーザーが存在するかどうかが判断できてしまう。誰にでもね。

セキュリティ的には、CAPTCHAを使ったりして大量のリクエストを防ぐというのも必要かなと思うけれど、
今回は、異常応答をしないようにしたい。
(あれ?Throttle機能が効いてるのかな??今度確認しよう。)

もともとのソースはこんな感じ

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException;

class PasswordResetLinkController extends Controller
{
    /**
     * Handle an incoming password reset link request.
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'email' => ['required', 'email'],
        ]);

        // We will send the password reset link to this user. Once we have attempted
        // to send the link, we will examine the response then see the message we
        // need to show to the user. Finally, we'll send out a proper response.
        $status = Password::sendResetLink(
            $request->only('email')
        );

        if ($status != Password::RESET_LINK_SENT) {
            throw ValidationException::withMessages([
                'email' => [__($status)],
            ]);
        }

        return response()->json(['status' => __($status)]);
    }
}

Password::sendResetLink でリセットリンクを送信して、その戻り値を判断して、異常応答か正常応答かを判断している。

異常応答の種類は、ここだけではわからないので、sendResetLink 関数を探す。
検索したら、「backend/vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php」の模様。

応答の種類は
・PasswordBroker::INVALID_USER(Password::INVALID_USER の同じもの)
・PasswordBroker::RESET_THROTTLED(Password::RESET_THROTTLED の同じもの)
・PasswordBroker::RESET_LINK_SENT(Password::RESET_LINK_SENT の同じもの)
の3種類。

PasswordBroker::RESET_THROTTLEDはrecentlyCreatedToken($user)で判定しているので、最近トークンを発行した場合に返されるのかな。
これも、2回ずつランダムなメールアドレスを送信した場合に、ユーザーの存在有無を判断できてしまうので、無視したいところだけれど、本当のユーザーが2回連続で送信したい場合も存在する(1回目は受信拒否設定の都合で受信できなかったとか。)
今回は、config/auth.phpの[‘passwords’][‘users’][‘throttle’]で前回トークンを発行してから何分間発行できないようにするかを設定できるようなので、0にして連続のトークン発行をできるようにする。

ということで、
正常終了しても、ユーザーが見つからなくても、{status: “ok”}を返すようにする。

        // if ($status != Password::RESET_LINK_SENT) {
        //     throw ValidationException::withMessages([
        //         'email' => [__($status)],
        //     ]);
        // }

        return response()->json(['status' => 'ok']);
    }
}
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_reset_tokens',
            'expire' => 60,
            'throttle' => 0,
        ],
    ],

ちなみに、、、

連続してトークンを発行したときは、古いトークンは新しいトークンで上書きされる仕様の模様。

ここまでやってみて

スターターキットはいち早くアプリケーションの機能を実装できるという点ではいいのだろうけど、スターターキットを参考にして機能を実装していった方がいいのかなーと思ってみたりする。