如何在 Javascript 生成的 HTML 表单中包含 Django 1.2 的 CSRF 令牌?
Posted
技术标签:
【中文标题】如何在 Javascript 生成的 HTML 表单中包含 Django 1.2 的 CSRF 令牌?【英文标题】:How do I include Django 1.2's CSRF token in a Javascript-generated HTML form? 【发布时间】:2011-04-15 10:36:52 【问题描述】:我最近升级到 Django 1.2.3,我的上传表单现在已经损坏。每当我尝试上传时,我都会收到“CSRF 验证失败。请求中止”。错误信息。
阅读 Django's documentation 关于这个主题后,它指出我需要在我的模板中的 html <form>
中添加 % csrf_token % 模板标签。不幸的是,我的<form>
是通过 javascript 生成的(特别是面板上 ExtJs 的“html”属性)。
长话短说,当我的 <form>
未包含在 Django 模板中时,如何将所需的 CSRF 令牌标签添加到我的 <form>
?
【问题讨论】:
【参考方案1】:这将使用 csrf 令牌或在需要时自动生成一个新令牌。它将处理页面上的所有表单提交。如果您有非现场表单,则需要确保它们不会运行此代码。
<script>
$(document).on('submit', 'form[method=post]', function()
if(!document.cookie.match('csrftoken=([a-zA-Z0-9]32)'))
for(var c = ''; c.length < 32;) c += 'abcdefghijklmnopqrstuvwxyz'.charAt(Math.random() * 26)
document.cookie = 'csrftoken=' + c + '; path=/'
if(!this.csrfmiddlewaretoken) $(this).append('<input type="hidden" name="csrfmiddlewaretoken">')
$(this.csrfmiddlewaretoken).val(document.cookie.match('csrftoken=([a-zA-Z0-9]32)')[1])
)
</script>
需要 jQuery 1.7+
【讨论】:
【参考方案2】:最简单的方法是使用 django 在您的页面上创建一个不做任何事情的隐藏表单。然后使用 JavaScript 获取表单,特别是表单中的令牌输入。最后,将该令牌输入插入或复制到您动态生成的表单中。
下面是两个示例,说明如何为 JavaScript 发布令牌。
<input id="csrf_token" value=" csrf_token "/>
<script type="text/javascript">
var CSRF_TOKEN = document.getElementById('csrf_token').value;
</script>
或
<script type="text/javascript">
var CSRF_TOKEN = " csrf_token ";
</script>
【讨论】:
@Huuuze:将csrf_token
放在模板中某处,并在表单构建期间使用JavaScript 对其进行解析。【参考方案3】:
这可能并不理想,但对我来说这是最快的解决方案。在“正文”底部的主模板中,我向我的库中添加了一个 javascript 函数。
<script type="text/javascript">
MyToolkit.Utils.getCSRFToken = function ()
return "% csrf_token %";
;
</script>
【讨论】:
该标签返回一个隐藏的 div。我想你的意思是 csrf_token 【参考方案4】:更好的解决方案是从视图/模板生成js文件的代码。
然后,在视图中,您可以像这样在上下文中设置 csrf 令牌...
from django.core.context_processors import csrf
context = RequestContext(request)
context.update(csrf(request))
然后,在模板中,您可以使用 csrf_token
获取 csrf 令牌的原始值,然后使用它在表单中构建一个名为 csrfmiddlewaretoken
的隐藏字段。
【讨论】:
【参考方案5】:另一种选择是使用 Ext 调整 the Django docs 中显示的基于 cookie/header 的解决方案 - 如果您有很多模板并且不想更改每一个模板,则更可取。
只需将以下 sn-p 放入您的 overrides.js(或您放置全局修改的任何位置):
Ext.Ajax.on('beforerequest', function (conn, options)
if (!(/^http:.*/.test(options.url) || /^https:.*/.test(options.url)))
if (typeof(options.headers) == "undefined")
options.headers = 'X-CSRFToken': Ext.util.Cookies.get('csrftoken');
else
options.headers.extend('X-CSRFToken': Ext.util.Cookies.get('csrftoken'));
, this);
(编辑:Ext已经有cookie读取功能,无需复制)
【讨论】:
我需要在动态生成的表单中做/添加什么吗? @john2x:不,您只需将代码放入您的 overrides.js 中。如果你不熟悉 overrides.js 的概念,下面的博客是一个好的开始:edspencer.net/2009/07/extoverride-monkey-patching-ext-js.html +1。太棒了,当我找到这个答案时,我也在思考同样的问题! 另外值得注意的是,如果您的模板不包含% csrf_token %
,csrftoken
cookie 可能不存在。要强制始终设置 cookie,请使用导入为 from django.views.decorators.csrf import ensure_csrf_cookie
的 @ensure_csrf_cookie
装饰您的视图。见docs.djangoproject.com/en/1.8/ref/csrf/#ajax【参考方案6】:
您POST
ing 的视图是否也回复GET
?因为 JS 代码可以向相关视图发出 GET
请求并解析输出以提取 CSRF 令牌。我的 JS-fu 很弱,我不确定从客户端进行解析的效果如何。
有关广泛的相关示例,请参阅this question。在这种情况下,用户尝试使用 Python 脚本 POST
并由于同样的原因而失败。解决方案是相同的,只是他必须使用 Python 脚本而不是 JavaScript。
【讨论】:
以上是关于如何在 Javascript 生成的 HTML 表单中包含 Django 1.2 的 CSRF 令牌?的主要内容,如果未能解决你的问题,请参考以下文章
任何人都有一个很好的解决方案来抓取带有 Javascript 生成的内容(在本例中为 HTML 表)的页面的 HTML 源代码? [关闭]
如何在生成的 HTML 页面中隐藏 JavaScript 注释? [关闭]
如何防止用户生成的 HTML 中的 Javascript 注入攻击