2010-09-21 34 views
10

我最近升级到Django 1.2.3,现在我的上传表单已经损坏。无论何时我尝试上传,我都会收到“CSRF验证失败,请求已终止。”错误信息。如何在Javascript生成的HTML表单中包含Django 1.2的CSRF令牌?

在阅读了关于此主题的Django's documentation之后,它声明我需要在模板中的HTML <form>内添加{%csrf_token%}模板标记。不幸的是,我的<form>是通过JavaScript(特别是面板上的ExtJs的“html”属性)生成的。

长话短说,当我的<form>未包含在Django模板中时,如何将所需的CSRF令牌标记添加到我的<form>

回答

13

另一种选择是将基于cookie/header的解决方案与the Django docs中显示的解决方案一起使用,如果您有很多模板并且不想更改每一个模板,则更可取。

刚落,下面的代码片段在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); 

(编辑:内线已经有了cookie的阅读功能,无需重复它)

+0

我是否需要在动态生成的表单中添加/添加任何内容? – john2x 2011-04-06 09:57:05

+1

@ john2x:不,你只需要把代码放入你的overrides.js。如果您不熟悉overrides.js的概念,那么以下博客是一个不错的开始:http://edspencer.net/2009/07/extoverride-monkey-patching-ext-js.html – chrisv 2011-04-07 11:03:31

+0

+1。辉煌的是,当我找到这个答案时,我正在思考相同的问题! – Swanand 2012-04-05 15:57:51

9

最简单的方法是使用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> 
+0

你能提供一个例子吗? – Huuuze 2010-09-22 02:23:26

+0

为什么选择投票? – 2010-09-22 05:45:16

+0

@Huuuze:将'{csrf_token}'放在模板的某处,并在构建表单时用JavaScript解析它。 – 2010-09-22 05:45:54

0

请问你是POST ING认为还应对GET?因为JS代码可以向有问题的视图发出GET请求,并解析输出以提取CSRF令牌。我的JS-fu很薄弱,我不确定你如何能够最好地从客户端进行解析。

对于广泛相关示例见this question。在这种情况下,用户正在尝试使用Python脚本POST并因相同的原因失败。解决方案是一样的,除了他必须从Python脚本而不是JavaScript来完成。

1

更好的解决方案是从视图/模板生成js文件的代码。

然后,在视图中可以设置CSRF令牌起来像这样的背景下...

from django.core.context_processors import csrf 
context = RequestContext(request) 
context.update(csrf(request)) 

然后,在模板中,你可以使用{{ csrf_token }}得到CSRF令牌的原始值,然后用它在名称为csrfmiddlewaretoken的表单中建立一个隐藏字段。

0

这可能并不理想,但它对我来说是最快的解决方案。在“body”底部的主要模板中,我向库中添加了一个javascript函数。

<script type="text/javascript"> 
    MyToolkit.Utils.getCSRFToken = function() { 
     return "{% csrf_token %}"; 
    }; 
</script> 
+0

该标签返回一个隐藏的div。我认为你的意思是{{csrf_token}} – Tom 2012-06-07 18:37:31

0

这将使用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+