2013-03-30 46 views
0

我一直從Django獲得403錯誤。Django/JQuery CSRF:403錯誤

我設置了我的settings.py以使用CSRF保護,並在我的模板中使用了csrf_token標記。

這裏是JS文件,我只是HTML頭之後包括:http://bpaste.net/show/87791/

用Firebug我可以檢查CSRF的cookie是存在的。後來在頁面上,用戶點擊一個按鈕,觸發此代碼:

myFunction: function() { 
    $.ajax({ 
    type: 'POST', 
    url: window.localtion.href + 'myajaxview', 
    async: false 
    }); 
} 

我使用從TemplateView繼承顯示此頁面的簡單類基於視圖。 'myajaxview'繼承自View和一個JSON Mixin。但是,由於django無法驗證CSRF令牌,所以其代碼從未執行過。

在我看來,ajax不會像POST應用那樣發送POST標頭。或者我錯過了什麼?

編輯:在調用$ .ajax()POST函數之前,我調用了$ .ajaxSetup調用,並且它工作正常。我試圖把它移到其他地方,但它失敗了。這個問題與我認爲的Django比Ajax更相關。 所以,我的問題仍然存在,我不想在每個$ .ajax調用之前放置$ .ajaxSetup調用,我不認爲這是事情完成的方式,我不想重複自己。所以這只是一個解決方法,我正在尋求解決方案。

+0

你可能想看看csrf_exempt [這裏](https://docs.djangoproject.com/en/1.2/ref/contrib/csrf/) –

+0

已經看到了,如果你看看我在bpaste上的代碼,它幾乎是一樣的。區別在於我將其作爲外部.js文件包含在內。由於我想共享該功能,並且每次在每個模板中執行ajax請求時都不包含相同的代碼。也許這是問題?在使用ajax時,在哪裏放置csrf_token?以及在哪裏放置getCookie代碼(即:只有當我做錯了)? – Aki

回答

0

謝謝你的幫助。答案是非常討厭的,我通過一個簡單的例子來測試ajaxSetup + ajax,然後增加了更多的複雜度來匹配我的原始代碼。

這是因爲jquery工具。當我開始使用bootstrap-twitter時,我看到他們建議將JavaScript包含在頁面末尾。所以我把jquery-tools.js包括在內。我不知道在這個腳本文件中調用了$ .ajaxSetup是否超出了我自己的範圍。

解決的辦法是把jquery工具包括在頂層。然而在這一點上,我不確定它會與我的代碼有多大的衝突。因爲我需要爲每個Ajax請求設置ajaxSetup。

我花了一天的時間才知道,我在#jquery和#django上,很多人試圖找出解決方案。如果你有一個複雜的代碼庫,你不能共享,並且你想解決一個問題,這裏是我的建議:試着讓最簡單的例子工作,並改變它,直到它匹配你失敗的設置。它會節省每個人的時間,尤其是你自己的時間。

0

首先,您是否檢查CSRF代碼是否實際發送到服務器?如果是,服務器是否希望散列值位於後置值或標頭中?現在你設置請求頭。 如果兩者都不能解決問題,請驗證服務器是否知道正確的散列。當客戶端發送正確的散列並且服務器將NULL作爲散列時,則驗證將失敗。

+0

csrf代碼位於cookie中。但根據JS代碼,它應該在請求頭部,它不是。所以我會說CSRF代碼不會發送到服務器,這是我懷疑的,但我不知道爲什麼。 – Aki

+0

您是否驗證cookie'csrftoken'是否存在? – f4der

+0

它存在於網頁和cookies中。但不在POST請求的HTTP標頭中。我用一些額外的信息更新了我的問題。 – Aki

2

這是代碼的片段,我認爲你正在尋找

var csrfToken = $('input[name="csrfmiddlewaretoken"]').val(); 
$.ajax({ 
    url: 'blah.com/', 
    //snipped for brevity 
    csrfmiddlewaretoken: csrfToken, 
    success: function(data){ doStuff(); } 
}); 

這是我爲了用什麼可以做的jQuery AJAX調用一個Django應用程序。 希望它的作品!

+0

我很感激。我可以使用getCookie()而不是你的方法來獲得csrfToken嗎?但是,仍然困惑於爲什麼xfer.setRequestHeader()在beforeSend()中不起作用。如果我讓它工作,那麼我不需要手動添加csrfmiddlewaretoken。 – Aki

+0

你可以用它來獲得csrf標記,但是xhr.beforesend設置對我來說也不起作用。我相信這是因爲使用動態加載的表單或dom元素時,csrf_token沒有正確生成。我會在今天晚些時候看到它,併爲您提供更新:) –

+0

看起來它不能很好地工作,雖然它在官方的django文檔上。我想我找到了一個解決方案,使其工作,但我不知道我解決了每個人的問題,因爲我的具體情況。 – Aki

3
myFunction: function() { 
    $.ajax({ 
    type: 'POST', 
    data: { 
    'csrfmiddlewaretoken': '{{csrf_token}}' 
    }, 
    url: '/myajaxview/', 
    async: false 
    }); 
} 
+0

這就像limelights的答案,它的工作原理我猜並且會幫助其他人,但我試圖按照文檔告訴它的方式來做:在每個XMLHttpRequest上,將自定義X-CSRFToken標頭設置爲CSRF標記的值。這就是爲什麼我與beforeSend()..奮鬥 – Aki

+0

它現在的作品。我認爲最難的部分是確保beforeSend()不被庫重寫,特別是在使用異步包含時。但現在它適用於我(請參閱我的答案)。感謝您的輸入,但我仍然可能在某些情況下使用它! – Aki

0

我解決了這個問題,只要DOM準備就緒,然後重新加載AJAX,就可以通過計算令牌的值。

javascript代碼使用reload_ajax()函數來處理標記,以及在初始頁面加載和隨後的AJAX調用時需要刷新的任何其他事物。

<script type="text/javascript"> 

function reload_ajax() { 
    // Useful on initial page load, and after calling AJAX. 
    $("input#token").val("{{ csrf_token }}"); 
} 

$(document).ready(function() { 
    $("form#stats").unbind("submit");  // Prevents calling document-ready multiple times 
    $("form#stats").submit(function(event) { 
     event.preventDefault(); 
     $.ajax({ 
      type:"POST", 
      url: $(this).attr("action"), 
      data: $(this).serialize(),  // Serialize the form 
      dataType: "json", 
      success: function(response){ 
       $("#stats_ajax").html(response.html); // Object to refresh after AJAX 
       reload_ajax(); 
      } 
     }); 
     return false; 
    }); 

    reload_ajax(); 
}); 
</script> 

我使用兩個HTML文件, 在main.html中,我的JavaScript代碼之上,並執行以下操作:

<div id="stats_ajax"> 
    {% include "stats_ajax.html" %} 
</div> 

在stats_ajax.html,我有實際的形式(加上其他的事情,我需要刷新)

<form id="stats" action="/main/" method="post"> 
    <!-- The value will be inserted when the DOM reloads. --> 
    <input id="token" type="hidden" name="csrfmiddlewaretoken" value="" /> 
    <!-- Other input elements --> 
    <button type="submit">Submit</button> 
</form> 

在我的views.py文件,

# Not all imports may be needed for this example 
from django.http import HttpResponse 
from django.shortcuts import render, redirect 
from django.template.loader import render_to_string 
import json 

def main(request): 
    # This request should only be posting AJAX 
    if request.is_ajax(): 
     data = {} 
     data["message"] = "Awesome" 
     # This is the template to load on the DOM object to update 
     html = render_to_string("stats_ajax.html", data) 
     res = {"html": html} 
     return HttpResponse(json.dumps(res), mimetype='application/json') 

    # Handle GET to this view 
    return redirect("/main") 

最後,我的urls.py有

# Replace "application_name" with your own value 
url(r'^main', 'application_name.views.main'), 
+0

做了所有事情,但錯誤((Forbidden(403) CSRF驗證失敗。請求中止。「GET/main HTTP/1.1」200 1111 「POST/main HTTP/1.1」403 2294 – Olga