2

私は WTForms と Flask を Flask-WTF 拡張で使用しています

私のフォームは次のようになります。

class CommentForm(Form):
    body = TextAreaField('Body', [validators.Length(min=4, max=300)])
    entity_id = HiddenField('Entity ID', [validators.required()])

Jinja2 テンプレート:

 <form method="POST" action="{{ request.url }}#comment-question" id="comment-question">
     <div>{{ comment_form.body }} <button type="submit">Submit</button></div>
     {{ comment_form.entity_id(value=question.id) }}
     {{ comment_form.hidden_tag() }}
 </form>

レンダリングされたフォーム:

<form method="POST" action="http://localhost:5000/answers/1/question-0#comment-question" id="comment-question">
  <div><textarea id="body" name="body"></textarea> <button type="submit">Submit</button></div>
  <input id="entity_id" name="entity_id" type="hidden" value="1">
  <div style="display:none;"><input id="csrf_token" name="csrf_token" type="hidden" value="20120507081937##ee73cc3cfc053266fef78b48cc645cbf90e8fba6"><input id="entity_id" name="entity_id" type="hidden" value=""></div>
</form>

フォームの「アクション」を変更してリダイレクトを行わずに、ブラウザーの更新ボタンのクリックでフォームの二重送信を防ぐことは可能ですか?

4

1 に答える 1

4

WTForms や Flask を使用した経験はあまりありませんが、Django クラスベースのビューは、POST の後にリダイレクトすることで二重投稿を防止するため、リダイレクトを実行することがこの種の方法であると想定していました。

1 つの代替方法は、一意のトークンを生成し、それをフォーム パラメーターに添付することです (CSRF トークンによく似ています)。この値をキャッシュし、フォーム送信時に照合します。Django のかなり原始的な例がここにあります

編集:サンプルコード

フォームの送信が成功した後にリダイレクトを実行するだけですが、CSRF 保護に関するこの Flask スニペットから大量に借用するフォーム トークンを生成する例を次に示します。

# yourapp/views/filters.py

import random
from string import ascii_letters, digits

from flask import request, session, redirect
from yourapp import app


def generate_form_token():
    """Sets a token to prevent double posts."""
    if '_form_token' not in session:
        form_token = \
            ''.join([random.choice(ascii_letters+digits) for i in range(32)])
        session['_form_token'] = form_token
    return session['_form_token']


@app.before_request
def check_form_token():
    """Checks for a valid form token in POST requests."""
    if request.method == 'POST':
        token = session.pop('_form_token', None)
        if not token or token != request.form.get('_form_token'):
            redirect(request.url)


app.jinja_env.globals['form_token'] = generate_form_token

そしてあなたのテンプレートで:

<!-- Again, I've never used WTForms so I'm not sure if this would change when using that app. -->
<input type='hidden' name='_form_token' value='{{ form_token() }}' />

スニペットで CSRF 保護メソッドを使用しても、ほぼ同じ効果が得られることに注意してください (ただし、上記のコードはリダイレクトを実行しますが、スニペットは 403 を返します)。

しかし、これは本当に疑問を投げかけます。無効なトークンでリダイレクトを実行している場合、この複雑さをすべて取り除き、フォームの送信が成功したときにリダイレクトしないのはなぜですか?

于 2012-05-07T05:46:13.717 に答える