2010-09-21 111 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+