40

我正在使用 Flask-WTF:

这是我的表格:

from flask.ext.wtf import Form, TextField

class BookNewForm(Form):
    name = TextField('Name')

这是控制器:

@book.route('/book/new', methods=['GET', 'POST'])
def customers_new():
    form = BookNewForm()
    if form.is_submitted():
        print "submitted"
    if form.validate():
        print "valid"
    if form.validate_on_submit():
        flash("Successfully created a new book")
        return redirect(url_for('.books_show'))
    return render_template('views/books_new.html', form=form)

现在的问题是,如果您查看我的打印语句,它总是打印提交,但它永远不会打印有效并且 validate_on_submit() 永远不会执行。为什么?

4

7 回答 7

70

您没有在 HTML 表单中插入 CSRF 字段。

<form method=post>
    {{ form.csrf_token }}
    {{ form.name }}
    <input type=submit>
</form>

添加form.csrf_token到模板 ( docs ) 后,表单将按预期进行验证。

在验证表单后添加print(form.errors)以查看引发的错误。 errors在验证之前将为空。在这种情况下,有一个关于丢失的错误

@book.route('/book/new_no_csrf', methods=['GET', 'POST'])
def customers_new_no_csrf():
    form = BookNewForm()
    print(form.errors)

    if form.is_submitted():
        print "submitted"

    if form.validate():
        print "valid"

    print(form.errors)

    if form.validate_on_submit():
        flash("Successfully created a new book")
        return redirect(url_for('.books_show'))

    return render_template('books_new.html', form=form)
{}
submitted
{'csrf_token': [u'CSRF token missing']}
127.0.0.1 - - [29/May/2012 02:01:08] "POST /book/new_no_csrf HTTP/1.1" 200 -
127.0.0.1 - - [29/May/2012 02:01:08] "GET /favicon.ico HTTP/1.1" 404 -

我在 GitHub 上创建了一个示例。

于 2012-05-29T04:47:15.920 回答
16

你可以打印错误

print form.errors

或者

app.logger.debug(form.errors)

如果你得到 csrf-error,你应该在你的模板中设置form.csrf_token 。

于 2012-05-23T23:10:19.623 回答
4

当我试图在我的模板中渲染一个FormField被迭代的对象时,我遇到了这个问题。FieldList我必须嵌入两个 hidden_​​tag 元素,一个用于FieldList表单,一个用于FieldForm表单,在模板注释中搜索关键字“HIDDEN TAG”

class ParamRangeForm( FlaskForm ):
    minX = FloatField( )
    maxX = FloatField( )

class ParamRangesForm( FlaskForm ):
    paramRanges = FieldList( FormField( ParamRangeForm ) )
    submit      = SubmitField( 'Submit' )

    def loadParams( self ) :
        for paramName in ["p1" , "p2" , "p3", "p4"] :
            prf = ParamRangeForm( )
            prf.minX = -100.9#float('-inf')
            prf.maxX = 100.5#float('-inf')
            self.paramRanges.append_entry( prf )

...

  <form action="" method="POST" enctype="multipart/form-data">
    {{ rangesForm.hidden_tag() }} <!--#### HIDDEN TAG #1 -->
    <table>
      <!--Print Column Headers-->
      <thead>
      <tr>
        <th class="ColumnHeader">Parameter</td>
        <th class="ColumnHeader">Min</td>
        <th class="ColumnHeader">Max</td>
      </tr>
      </thead>

      <!--Print Parameter Rows-->
      <tbody>
      {% for paramRange in rangesForm.paramRanges %}
        <tr>
          {{ paramRange.hidden_tag() }} <!--#### HIDDEN TAG #2 -->
          <td>p{{ loop.index }}</td>
          <td>{{ paramRange.minX }}</td>
          <td>{{ paramRange.maxX }}</td>
        </tr>
      {% endfor %}
      </tbody>
    </table>
    </div>
    {{ rangesForm.submit() }}
  </form>
于 2017-07-04T00:15:33.900 回答
2

在模板 html 文件中的标记之后插入:

 {{ form.csrf_token }} 
于 2014-09-25T07:08:51.573 回答
1

如果我在每次请求之前都没有登录,我正在清除烧瓶会话。这导致了这个问题。

@main.before_request
def before_request():
    if not current_user.is_authenticated():
        # TODO clean sessions may cause CSRF missing issue
        session.clear()
        print "Session Cleared"
        return redirect(url_for('auth.login'))
于 2014-08-18T01:11:32.260 回答
0

我认为 API 已经改变。也许尝试改变

from flask.ext.wtf import Form

到:

from flask_wtf import Form
于 2018-08-15T20:10:59.137 回答
0

我花了几个小时调试 Flask-WTF 的验证问题。与许多其他问题一样,问题是 CSRF 验证问题。但是,我的问题不是由我发现的任何常见问题引起的。

CSRF 的标准 Flask-WTF 实现需要将件事传递给浏览器。

一:隐藏的 CSRF 表单域 eg

<input id="csrf_token" name="csrf_token" type="hidden" value="ImYzODdmZTdhYTRlMmNkYWRjYmRlYWFmZjQxMDllZTQ1OWZmYzg3MTki.XKvOPg.gUCkF9j-vg0PrL2PRH-v43GeHu0">

二:会话cookie HTTP响应头 例如

Set-Cookie: session=eyJjc3JmX3Rva2VuIjoiZjM4N2ZlN2FhNGUyY2RhZGNiZGVhYWZmNDEwOWVlNDU5ZmZjODcxOSJ9.XKvOPg.a3-W62MHvaGVkv2GYCi-dgpLE3Y; HttpOnly; Path=/

如果缺少其中任何一个,浏览器将无法发送正确的 CSRF 验证。当然,这反过来会导致表单验证失败。

如果csrf_token表单中存在隐藏字段但缺少会话cookie,则提交表单时您将收到以下响应...

Bad Request
The CSRF session token is missing.

在我的情况下,由于我的代码中的错误,会话 cookie 丢失了。我需要在整个 Flask 站点中提供自定义 HTTP 标头。我像这样包含它...

class LocalFlask(Flask):

    def process_response(self, response):
        response.headers['my-header'] = 'My Header Value'
        return response

app = LocalFlask(__name__)

然而,这会导致任何依赖该Flask.response.headers方法的东西失败。其中之一是 Flaks-WTF 设置会话 cookie HTTP 标头。

这可以通过将super()方法添加到LocalFlask类中来解决,以便它继承Flask类的方法。

class LocalFlask(Flask):

    def process_response(self, response):
        response.headers['my-header'] = 'My Header Value'
        #LocalFlask inherits methods from Flask
        super(LocalFlask, self).process_response(response)
        return response

app = LocalFlask(__name__)
于 2019-04-09T10:34:50.820 回答