如何在jinja2模板引擎中实现csrf_token保护?

32
在 Django 模板中,我使用了:
<form action="/user" method="post">{% csrf_token %}
    {{ form.as_p|safe }}
    <input type="submit" value="Submit" />
</form>

但是当我更改为 jinja2模板引擎 时,出现错误:

 Encountered unknown tag 'csrf_token'

我的问题是:jinja2中是否需要csrf_token保护?

如果需要,如何实现?

提前致谢!

7个回答

53

看起来Jinja2的工作方式有所不同:

使用<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">, 而在Django模板中您使用{% csrf_token %}

来源:http://exyr.org/2010/Jinja-in-Django/


这个也可以与django-jinja Python库一起使用。(一个帮助库,使过渡到Jinja2变得轻松)。 - D Left Adjoint to U
{{ csrf_input }} 是一种更短的替代方式,正如 @Isowen 的答案所解释的那样。 - Alan Evangelista

36

我知道这是一个旧的问题,但我想更新一下使用 Django 1.8+ 中可用的新的 django.template.backends.jinja2.Jinja2 时支持 csrf_token 的正确方法。 使用 django 模板后端,您将会调用 {% csrf_token %} ,但是使用 Jinja2 后端,您需要使用 {{ csrf_input }} 来调用它(您可以仅获取令牌值而不是令牌输入,使用 {{ csrf_token }} )。

您可以在 django.template.backends.jinja2.Jinja2源代码中查看详细信息。


2
当使用宏来渲染表单时,为了传递 csrf_input,你需要在导入它们时加上上下文,例如:{% from "bootstrap/forms/horizontal.html" import render_form with context%}。有关更多信息,请参见 Jinja2 导入可见性 - Janusz Skonieczny

2
在使用Django 2.x与Jinja2模板引擎时,您可以使用{{ csrf_token }}获取令牌的值,使用{{ csrf_input }}获取完整的隐藏输入标签。
来源:https://django.readthedocs.io/en/2.1.x/ref/csrf.html 示例:
<form action="..." method="post">
  {{ csrf_input }}

   ...
</form>

更新链接:https://docs.djangoproject.com/en/3.1/ref/csrf/#using-csrf-in-jinja2-templates - Alex Budovski

0

我使用Coffin。 并且在使用时遇到了同样的问题:

from coffin.shortcuts import render_to_response
return render_to_response('template_name_here.html', context)

尝试使用以下替代方案:

from coffin.shortcuts import render
return render(request, 'template_name_here.html', context)

0

您不再需要做任何特殊的事情了。csrf_token 已经在 django-jinja 中得到支持,并且可以直接使用。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>test</title>
  </head>
  <body>
    <p>This should add a hidden input tag with the token. use it in your forms</p>
    {% csrf_token %}
  </body>
</html>

当我以这种方式使用它时,我遇到了("Encountered unknown tag 'csrf_token'. Jinja was looking for the following tags: 'endblock'. The innermost block that needs to be closed is 'block'.",)错误。 - ruslaniv
1
很奇怪,我正在使用它:<form method="post">{% csrf_token %} {{ form.as_p() }} ... 你在settings.py的模板部分中是否正确列出了django_jinja.builtins.extensions.CsrfExtension? - Emilio
@Emilio 感谢您的评论。它很有用,但仅在模板后端为django_jinja时才有效。 - neuront

0

这段JS代码可以解决这个问题,它适用于Django和Jinja2,因为它是纯JavaScript处理post方法表单标签的方式,您可以通过探索它来自定义它。

我只是从已经存在的cookie中获取CSRF令牌,并在表单标签中使用它。

let getCookie = (name) => {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}


$(()=>{
    formTags = document.querySelectorAll('[method="POST"]')
    
    let csrfToken = getCookie('csrftoken')

    

    Array.from(formTags).forEach(formTag=>{

        var inputTag = document.createElement('input')

        inputTag.setAttribute('type', 'hidden')
        inputTag.setAttribute('name', 'csrfmiddlewaretoken')
        inputTag.setAttribute('value', [csrfToken])
    
        formTag.appendChild(inputTag)

    })
})

-1
我曾经遇到过同样的问题,我注意到默认加载的处理器列表中没有CSRF上下文处理器。在setting.py文件中将'django.core.context_processors.csrf'添加到TEMPLATE_CONTEXT_PROCESSORS后,我就可以正常使用{% csrf_token %}模板标签了。

他说使用jinja2而非django模板。 - tcpiper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接