質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

2回答

5025閲覧

laravelでformデータの多重送信対策をしたい

seibi02

総合スコア15

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

1グッド

3クリップ

投稿2019/02/23 07:26

編集2019/02/23 09:22

前提

Laravel5.7を使用して学習のため自作でログイン機能などを作成しております。
ですのでmake:authは使っていません。

パスワードを忘れてしまったユーザーに対して登録したメールアドレスを入力してもらう事で
パスワード再設定のご案内メールを送るページでの質問です。

実現したいこと

送信ボタンの連打、またはブラウザバックによるメールの多重送信を防ぎたい。

発生している問題

$request->session()->regenerateToken();

上記を使えば重複したリクエストが発生した場合、
リクエスト中のトークン($request->_token)と
セッションに保存されているトークン($request->session()->token())が
一致しなくなりエラーが返され多重で送信されないという事まで調べてわかりました。
(違っていたらご指摘お願い致します)

しかし私のコードでは連打すると1通目と2通目のセッション、トークン共に全て値が同じで
ブラウザバックすると1通目と2通目の値は違うもののセッションとトークンは一致しており多重送信されてしまいます。

何が間違っているのかわからない為ご教授頂けたらと思います。

補足

今回はセッションとトークンの値を簡単に確認するために
メールの件名にセッション、内容にトークンを入れています。

該当のソースコード

view

1@extends('layouts.default') 2 3 4@section('content') 5<div class="container mt-5"> 6 <div class="row justify-content-center"> 7 <div class="col-md-8"> 8 <div class="card"> 9 <div class="card-header">{{'パスワードの再設定申請'}}</div> 10 <div class="card-body"> 11 <p>登録されているメールアドレスを入力し、送信ボタンを押して下さい。</p> 12 <form method="POST" action="{{ url('/auth/password/forgot') }}"> 13 @csrf 14 <div class="form-group row"> 15 <label for="email" class="col-md-4 col-form-label text-md-right">{{'メール'}}</label> 16 <div class="col-md-6"> 17 <input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required maxlength="100" autofocus> 18 @if ($errors->has('email')) 19 <span class="invalid-feedback" role="alert"> 20 <strong>{{ $errors->first('email') }}</strong> 21 </span> 22 @endif 23 @if (isset($message)) 24 <span class="invalid-feedback" role="alert"> 25 <strong>{{ $message }}</strong> 26 </span> 27 @endif 28 </div> 29 </div> 30 <div class="form-group row mb-0"> 31 <div class="col-md-8 offset-md-4"> 32 <button type="submit" class="btn btn-primary"> 33 {{'送信'}} 34 </button> 35 </div> 36 </div> 37 </form> 38 </div> 39 </div> 40 </div> 41 </div> 42</div> 43@endsection 44

controller

1public function sendForgetMail(Request $request) 2 { 3 $request->validate([ 4 'email' => 'required|string|email|max:100|exists:users,email', 5 ]); 6 $user = UsersTable::getUserData($request->email); 7 // トークン作成 8 $token = Common::createToken($request->email); 9 // URLの作成 10 $url = Common::fetchUrlForMail('auth/password/reset', $token); 11 // パスワードリセットテーブルに保存 12 TokensTable::insertPassToken($user->id, $token); 13 14 // メール送信 15 $mailer = new Mailer(); 16 //$mailer->sendMail($url, $request->email, 'パスワード再設定のご案内', 'emails.templates.password_reset_mail'); 17 $mailer->sendMail($request->_token, $request->email, $request->session()->token(), 'emails.templates.password_reset_mail'); 18 // 二重送信対策 19 $request->session()->regenerateToken(); 20 21 // 送信完了メッセージ 22 return view('auth.password.request_result'); 23 }
s8_chu👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/23 08:46

fromではなくformでは? 細かいですが名前が決まっているもののスペルミスは致命的になり得ます。正確に記載願います
seibi02

2019/02/23 09:24

タイトル修正しました。
guest

回答2

0

直接の問題解決にはなりませんが、発生している問題に書いてある

しかし私のコードでは連打すると1通目と2通目のセッション、トークン共に全て値が同じで ブラウザバックすると1通目と2通目の値は違うもののセッションとトークンは一致しており多重送信されてしまいます。

の部分について、同様のことを調べていましたので説明させていただきますね。

LaravelではSessionに保存されている値はリクエストの最初の方でStore(FileやMemcached)などから読み込まれ、その後Arrayとして保持されて、レスポンスを返す直前でStoreに書き込まれます。

つまり連打した場合にはリクエスト後にregenerateTokenは実行されますが、その後のStoreへの書き込みが終わっていない状態でさらにリクエストが始まるという動きになり、Storeに書き込ま得れるまえのtokenが読み出されるので一致してしまいます。

これはStartSessionというMiddlewareに実装が書かれていて、レスポンスを作成したあとにreturnする直前にsaveSessionしていることがわかります。

https://github.com/laravel/framework/blob/6.x/src/Illuminate/Session/Middleware/StartSession.php#L65

投稿2019/10/03 06:01

編集2019/10/03 06:09
KazuheiArai

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seibi02

2019/10/28 20:13

返信遅れてすみません 回答ありがとうございます。 つまり今のやり方ではlaravelの仕様上多重送信を防ぐことは不可能なんですね。。。
guest

0

キータにこんな記事がありました。

引用
送信ボタンダブルクリックでの二重送信防止
こんな感じのJavaScriptを仕込んでおくといいと思う。

Laravel 5で確認画面付き問い合わせフォームを作る - Qiita

投稿2019/02/23 07:50

DaisukeMori

総合スコア225

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seibi02

2019/02/23 07:56

回答ありがとうございます。 $request->session()->regenerateToken();による処理がどうしても出来ない場合は jsにて対策しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問