【问题标题】:WTForms double POST submit prevention on refresh flask-wtfWTForms 在刷新 flask-wtf 时双重 POST 提交预防
【发布时间】:2012-05-15 15:37:51
【问题描述】:

我使用带有 Flask-WTF 扩展的 WTForms 和 Flask

我的表格如下:

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>

是否可以在不更改表单“操作”并进行重定向的情况下防止在浏览器刷新按钮单击时双重提交表单?

【问题讨论】:

    标签: python flask wtforms double-submit-prevention


    【解决方案1】:

    我没有太多使用 WTForms 或 Flask 的经验,但是基于 Django 类的视图通过在 POST 之后重定向来防止重复发布,所以我认为执行重定向是处理这类事情的方法。

    另一种方法是生成一个唯一的令牌并将其附加到您的表单参数(很像 CSRF 令牌)。缓存此值并在表单提交时对其进行检查。 Django can be found here 的一个相当原始的示例。

    编辑:示例代码

    虽然我真的会在成功提交表单后执行重定向,但这里有一个生成表单令牌的示例,该令牌大量借用 this Flask snippet on CSRF protection

    # 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() }}' />
    

    请注意,在the snippet 中使用 CSRF 保护方法也可以实现几乎相同的效果(尽管上面的代码执行重定向,而 sn-p 返回 403)。

    但这确实引出了一个问题——如果您正在对无效令牌执行重定向,为什么不摆脱所有这些复杂性并在成功提交表单时重定向?

    【讨论】:

    • 只是想补充一点,这个解决方案永远不会处理更长的请求,并且会话存储在 cookie 中(Flask 中的默认值)。将会话移动到数据库或文件将有所帮助,以及在请求后禁用提交按钮。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2018-09-03
    • 2016-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 2018-01-21
    相关资源
    最近更新 更多