简体   繁体   English

如何:使用 Flask 在 WTForms 中动态生成 CSRF-Token

[英]Howto: Dynamically generate CSRF-Token in WTForms with Flask

I have a fruits form that has one FieldList object for the bananas:我有一个水果表单,它有一个用于香蕉的 FieldList 对象:

bananas = FieldList(FormField(BananaForm))

In the frontend, initially, I add one of those fields to the FieldList在前端,最初,我将这些字段之一添加到 FieldList

form.append_entry()

Now with Javascript I managed to create functions, that can dynamically add (plus button) or remove (minus button) the number of BananaForm fields that can be filled with information.现在使用 Javascript 我设法创建函数,可以动态添加(加号按钮)或删除(减号按钮)可以填充信息的 BananaForm 字段的数量。

FielstList automatically creates ids for all of its fields. FielstList 自动为其所有字段创建 ID。 So to do dynamical adding with js, I duplicate the HTML code and set the field id += 1, like:所以为了用js做动态添加,我复制了HTML代码并设置了字段id += 1,比如:

first field:第一个字段:

<tr>
  <td><input id="bananas-0-originCountry" type="text" /></td>
</tr>

duplicated field with += 1: += 1 的重复字段:

<tr>
  <td><input id="bananas-1-originCountry" type="text" /></td>
</tr>

When I name them accordingly like this and submitting the form, WTForms will automatically recognize the added fields in the backend (works fine).当我像这样相应地命名它们并提交表单时,WTForms 将自动识别后端中添加的字段(工作正常)。

So far so good, but here is my problem: For a form to be valid, I have to add CSRF-fields to every WTForm.到目前为止一切顺利,但这是我的问题:要使表单有效,我必须向每个 WTForm 添加 CSRF 字段。 In the Jinja template I do this with:在 Jinja 模板中,我这样做:

{{ form.hidden_tag() }}

However, when I just copy the HTML with my js function, I'm missing the CSRF-fields (because until submitted, the backend form object doesn't know about the added FormFields).但是,当我只是用我的 js 函数复制 HTML 时,我缺少 CSRF 字段(因为在提交之前,后端表单对象不知道添加的 FormFields)。 So how can I generate these CSRF-fields dynamically?那么如何动态生成这些 CSRF 字段呢? (An Ajax Request? If yes, how?) (Ajax 请求?如果是,怎么做?)

This should be a standard use case with forms and flask.这应该是带有表单和烧瓶的标准用例。 I hope my description was understandable, if not please let me know.我希望我的描述是可以理解的,如果不是,请告诉我。 Any help appreciated!任何帮助表示赞赏!

UPDATE: Here is my code更新:这是我的代码

JS-functions JS-函数

function addBanana(){
    // clone and insert banana node
    var node = document.getElementById("fruitTable");
    var trs = node.getElementsByTagName("tr");
    var tr = trs[trs.length-2];
    var tr2 = tr.cloneNode(true);
    tr.parentNode.insertBefore(tr2, tr);

    // in order to increment label and input field ids
    function plusone(str){
        return str.replace(
            new RegExp("-(\\d+)-", "gi"),
            function($0, $1){
                var i = parseInt($1) + 1;
                return "-" + i + "-";
            }
        );
    }

    // change inputs
    var inputs = tr.getElementsByTagName("input");

    for (var i = 0; i < inputs.length; i++){
        inputs[i].setAttribute("id", plusone(inputs[i].getAttribute("id")));
    }

    var minusbutton = 
        ['<td>',
        '<button class="btn" type="button" onClick="removeBanana()"><i class="icon-black icon-minus"></i></button>',
        '</td>'
        ].join('\n');

    // only append at the first add
    // second add automatically copies minus button
    if (trs.length < 6){
        tr.innerHTML += minusbutton
    }
}

function removeBanana(){
    var node = document.getElementById("fruitTable");
    var trs = node.getElementsByTagName("tr");
    var tr = trs[trs.length-2];
    var trParent = tr.parentNode;
    trParent.removeChild(tr);
}

Jinja Template:金贾模板:

<form method="POST" action="newsubmit">
  {{ form.hidden_tag() }}
  <table id="fruitTable" class="table">
    {{ render_field(form.description) }}
    <tr><td><h3>Bananas</h3></td></tr>
    {% set counter = 0 %}
    {% for banana in form.bananas %} 
      <tr>
        {{ banana.hidden_tag() }}
        {% set counter = counter + 1%}
        {% for field in banana if field.widget.input_type != 'hidden' %}
          {{ render_field_oneline(field) }}
        {% endfor %}
        {% if counter > 1 %} 
          <td>
            <button class="btn" type="button" onClick="removeBanana()"><i class="icon-black icon-minus"></i></button>
          </td>
        {% endif  %} 
      </tr>
    {% endfor %}
      <tr><td></td><td><button class="btn" type="button" onClick="addBanana()"><i class="icon-black icon-plus"></i></button></td></tr>
  </table>
<input class="btn btn-primary" style="margin-left:300px;"type="submit" value="Submit" />
</form>

Jinja Template Macros: Jinja 模板宏:

{% macro render_field_oneline(field) %}
<td>{{ field.label }}</td>
<td>{{ field(**kwargs)|safe }}
  {% if field.errors %}
  <ul class=errors>
    {% for error in field.errors %}
    <li>{{ error }}</li>
    {% endfor %}
  </ul>
  {% endif %}
</td>
{% endmacro %}

{% macro render_field(field) %}
<tr>
  {{ render_field_oneline(field) }} 
</tr>
{% endmacro %}

I discovered how it works:我发现它是如何工作的:

The CSRF-Tag can simply be copied. CSRF-Tag 可以简单地复制。 The id must be changed and incremented accordingly, but the hash may stay the same. id 必须相应地更改和递增,但哈希值可能保持不变。

I didn't think it was possible to have many Fields with the same CSRF-Tag hash, but it actually does!我认为不可能有许多具有相同 CSRF-Tag 哈希的字段,但实际上确实如此!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM