wtforms,CSRF,flask,FieldList

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了wtforms,CSRF,flask,FieldList相关的知识,希望对你有一定的参考价值。

在使用带有WTForms的FieldList时,我无法通过验证。我一直收到这个错误。 {'csrf_token': [u'CSRF token missing']}。问题是如果我在FieldList字段中没有任何要验证的数据,验证通过并且没有问题。但是,当我尝试使用任何数据验证表单时,我得到了该错误。

这是我的表格:

class FilterForm(wtf.Form):
    filter_value = wtf.TextField('Value', validators=[validators.Required()])
    filter_operator = wtf.SelectField('Operator', validators=[validators.Required()])
    filter_compare_value=wtf.TextField('Compare Value', validators=[validators.Required()])


class RedirectForm(wtf.Form):
    redirect_id = wtf.HiddenField('id')
    redirect_name = wtf.TextField('Name', validators=[validators.Required()])
    redirect_url = wtf.TextField('URL', validators=[validators.Required()])
    redirect_type = wtf.SelectField('Type', validators=[validators.Required()])
    redirect_method = wtf.SelectField('Method', validators=[validators.Required()])
    redirect_active = wtf.BooleanField('Is Active')
    redirect_filters_any = wtf.FieldList(wtf.FormField(FilterForm))
    redirect_filters_all = wtf.FieldList(wtf.FormField(FilterForm))

表单似乎正确显示并正常工作,直到我将数据添加到redirect_filters_anyredirect_filters_all

有没有办法禁用FieldList的csrf或将CSRF值传递给FieldList?我想保持启用CSRF保护,但似乎无法通过此验证问题。

这是Jinja2模板

{% extends "base.html" %}
{% set active_page = "endpoints" %}
{% block tail_script %}
<script src="/static/js/page/redirects.js"></script>
{% endblock %}
{% block content %}
<div class="row12">
    <div class="span12">
        <ul class="breadcrumb">
              <li><a href="{{ url_for('list_endpoints') }}">Endpoints</a> <span class="divider">/</span></li>
              <li><a href="{{ url_for('show_endpoint', id=endpoint_id) }}">{{endpoint_name}}</a> <span class="divider">/</span></li>
              {% if redirect_id != 'new' %}
              <li class="active">{{ form.redirect_name.data }}</li>
              {% else %}
              <li class="active">New</li>
              {% endif %}
        </ul>
        <form action="{{ url_for('edit_redirect', endpoint_id=endpoint_id, redirect_id=redirect_id) }}" class="form-horizontal" method="post">
            <legend>General</legend>
            {{ form.hidden_tag() }}
            <div class="control-group {% if form.redirect_name.errors %}error{% endif %}">
                <div class="control-label">{{ form.redirect_name.label }}</div>
                <div class="controls">
                    {{ form.redirect_name|safe }}
                    {% if form.redirect_name.errors %}
                    <span class="help-inline">
                         <ul class="errors">
                            {% for error in form.redirect_name.errors %}
                            <li>{{ error }}</li>
                            {% endfor %}
                        </ul>
                    </span>
                   {% endif %}
                </div>
            </div>
            <div class="control-group {% if form.redirect_type.errors %}error{% endif %}">
                <div class="control-label">{{ form.redirect_type.label }}</div>
                <div class="controls">
                    {{ form.redirect_type|safe }}
                    {% if form.redirect_type.errors %}
                    <span class="help-inline">
                         <ul class="errors">
                            {% for error in form.redirect_type.errors %}
                            <li>{{ error }}</li>
                            {% endfor %}
                        </ul>
                    </span>
                   {% endif %}
                </div>
            </div>
            <div class="control-group {% if form.redirect_active.errors %}error{% endif %}">
                <div class="control-label">{{ form.redirect_active.label }}</div>
                <div class="controls">
                    {{ form.redirect_active|safe }}
                    {% if form.redirect_active.errors %}
                    <span class="help-inline">
                         <ul class="errors">
                            {% for error in form.redirect_active.errors %}
                            <li>{{ error }}</li>
                            {% endfor %}
                        </ul>
                    </span>
                   {% endif %}
                </div>
            </div>
            <div class="control-group {% if form.redirect_method.errors %}error{% endif %}">
                <div class="control-label">{{ form.redirect_method.label }}</div>
                <div class="controls">
                    {{ form.redirect_method|safe }}
                    {% if form.redirect_method.errors %}
                    <span class="help-inline">
                         <ul class="errors">
                            {% for error in form.redirect_method.errors %}
                            <li>{{ error }}</li>
                            {% endfor %}
                        </ul>
                    </span>
                   {% endif %}
                </div>
            </div>
            <div class="control-group {% if form.redirect_url.errors %}error{% endif %}">
                <div class="control-label">{{ form.redirect_url.label }}</div>
                <div class="controls">
                    {{ form.redirect_url|safe }}
                    {% if form.redirect_url.errors %}
                    <span class="help-inline">
                         <ul class="errors">
                            {% for error in form.redirect_url.errors %}
                            <li>{{ error }}</li>
                            {% endfor %}
                        </ul>
                    </span>
                   {% endif %}
                </div>
            </div>
            <legend>Meet All Filters <a href="#" class="btn addAllFilter">Add</a></legend>
            <table class="stable-striped" id="all_filter_table">
                <tbody>
            {% for f in form.redirect_filters_all %}
                <tr style="vertical-align:top;">
                    <td>    
                        {{ f.filter_value }}
                        {% if f.filter_value.errors %}
                        <br>
                        <div class="control-group error">
                            <span class="help-inline">
                                 <ul class="errors">
                                    {% for error in f.filter_value.errors %}
                                    <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            </span>
                        </div>
                        {% endif %}
                    </td>
                    <td>    
                        {{ f.filter_operator }}
                        {% if f.filter_operator.errors %}
                        <br>
                        <div class="control-group error">
                            <span class="help-inline">
                                 <ul class="errors">
                                    {% for error in f.filter_operator.errors %}
                                    <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            </span>
                        </div>
                        {% endif %}
                    </td>
                    <td>    
                        {{ f.filter_compare_value }}
                        {% if f.filter_compare_value.errors %}
                        <br>
                        <div class="control-group error">
                            <span class="help-inline">
                                 <ul class="errors">
                                    {% for error in f.filter_compare_value.errors %}
                                    <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            </span>
                        </div>
                        {% endif %}
                    </td>
                    <td><a href="#" class="btn remove">Remove</a></td>
                </tr>
            {% endfor %}
                </tbody>
            </table>
            <legend>Meet Any Filters <a href="#" class="btn addAnyFilter">Add</a></legend>
            <table class="stable-striped" id="any_filter_table">
                <tbody>
            {% for f in form.redirect_filters_any %}
                <tr style="vertical-align:top;">
                    <td>    
                        {{ f.filter_value }}
                        {% if f.filter_value.errors %}
                        <br>
                        <div class="control-group error">
                            <span class="help-inline">
                                 <ul class="errors">
                                    {% for error in f.filter_value.errors %}
                                    <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            </span>
                        </div>
                        {% endif %}
                    </td>
                    <td>    
                        {{ f.filter_operator }}
                        {% if f.filter_operator.errors %}
                        <br>
                        <div class="control-group error">
                            <span class="help-inline">
                                 <ul class="errors">
                                    {% for error in f.filter_operator.errors %}
                                    <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            </span>
                        </div>
                        {% endif %}
                    </td>
                    <td>    
                        {{ f.filter_compare_value }}
                        {% if f.filter_compare_value.errors %}
                        <br>
                        <div class="control-group error">
                            <span class="help-inline">
                                 <ul class="errors">
                                    {% for error in f.filter_compare_value.errors %}
                                    <li>{{ error }}</li>
                                    {% endfor %}
                                </ul>
                            </span>
                        </div>
                        {% endif %}
                    </td>
                    <td><a href="#" class="btn remove">Remove</a></td>
                </tr>
            {% endfor %}
                </tbody>
            </table>
            {% if g.user.user_type == 'admin' %}
            <div class="control-group">
                <div class="controls">
                    <input class="btn btn-primary" type="submit" value="Save"/>
                    <a href="{{url_for('show_endpoint', id=endpoint_id)}}" class="btn">Cancel</a>
                </div>
            </div>
            {% endif %}
        </form>
    </div>
</div>
{% endblock %}
答案

问题似乎是Flask-WTForms Form实际上是wtforms.ext.SecureForm的子类 - 并且在表单上禁用csrf保护的唯一方法是在构造表单时将关键字参数csrf_enabled=False传递给表单。由于FormField实际上处理实例化表单,您可以:

  • 创建一个FormField的子类,它允许您传递表单关键字参数 要么
  • 为你的wtforms.Form子类flask.ext.wtforms.Form而不是FilterForm(只要你自己不显示FilterForm,你就不必担心CSRF)。
另一答案

在遇到同样的问题后,我想为上面的解决方案提供第三个选项

您还可以覆盖表单类中的构造函数以替换csrf_enabled的默认值。这样做的好处是,您可以使用与fieldlist成员相同的表单定义,以及通过传递csrf_enabled = True启用CSRF的独立表单。

class FilterForm(wtf.Form):
    field = wtf.Form ...

    def __init__(self, csrf_enabled=False, *args, **kwargs):
        super(FilterForm, self).__init__(csrf_enabled=csrf_enabled, *args, **kwargs)
另一答案

似乎csrf_enabled已被弃用。这是一个与Flask-WTForms 0.14.2一起使用的解决方案,部分基于leebriggs的answer。我创建了一个xNoCsrf子类,而不是在创建表单时传递参数,因为我不希望有人在他们想要的时候不小心忘记包含CSRF令牌。这样,您必须键入NoCsrf才能获得非CSRF版本。

class FilterForm(FlaskForm):
    <some stuff here>

class FilterFormNoCsrf(FilterForm):
    def __init__(self, *args, **kwargs):
        super(FilterFormNoCsrf, self).__init__(meta={'csrf':False}, *args, **kwargs)

Herecsrf类的meta字段的文档。

另一答案

从版本1.0开始,实现此目的的新方法如下:这将禁用表单的所有实例的CSRF令牌,因此请务必仅将其用作子表单。

class MyForm(FlaskForm):
    class Meta:
        csrf = False

    myfield = StringField("A Field")

以上是关于wtforms,CSRF,flask,FieldList的主要内容,如果未能解决你的问题,请参考以下文章

6---Flask-WTForms

flask-WTForms

Flask 框架:运用WTForms实现用户注册

Flask 中 AJAX 身份验证的 CSRF 保护

flask入门到起飞(五) flask-wtf使用

WTForms In Flask(WTForms在Flask中的应用)