初めに
私は、業務系のWebアプリケーションを作っているエンジニアです。
問合せでよくあるのが実行ボタン押しても、なかなか画面が変わらなくて、もう一度押したらエラーになりましたってやつ。
(なんで対策してないんだよ・・・)
てことで、Laravelにおける2重サブミット防止方法は以下の通りです。
2重サブミット対策
やることは2つ!
- バックエンドで、リクエストを受けてからトークンを再生成させる。そうすると、レスポンスが返る前に再度サブミットされるとトークンミスマッチ(419:TokenMismatchException)になる。
- フロントエンドで、ボタン押下後にボタンを非活性にする。
サーバーサイド
1. コントローラ
トークンを再生成した状態で、レスポンスが返る前に再度サブミットされるとトークンミスマッチが発生します。
※2〜3は、コード修正不要。
$session->regenerateToken();
2. ミドルウェア
トークンマッチをチェックする。
※標準で設定されてるので、追加は不要。
VerifyCsrfToken.php
public function handle($request, Closure $next)
{
if (
$this->isReading($request) ||
$this->runningUnitTests() ||
$this->inExceptArray($request) ||
$this->tokensMatch($request)
) {
return tap($next($request), function ($response) use ($request) {
if ($this->shouldAddXsrfTokenCookie()) {
$this->addCookieToResponse($request, $response);
}
});
}
throw new TokenMismatchException('CSRF token mismatch.');
}
3. カーネル
ここで、ミドルウェアを設定することでリクエストの際に処理されるようになります。
※標準で設定されてるので、追加は不要。
Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
フロントエンド
ボタン押下時、ボタンを非活性にし、フォームを送信する。
<input type="button" id="btn1" value="実行">
$("#btn1").click(function() {
$("#btn1").prop("disabled", true);
$("form").submit();
});