簡體   English   中英

在 Django 框架中發出 ajax Post 請求時出現 403 Forbidden 錯誤

[英]403 Forbidden error when making an ajax Post request in Django framework

我正在嘗試將 jquery 集成到我使用 Django 框架制作的 Web 應用程序中。 但是,我很難嘗試進行簡單的ajax調用。 我的模板文件包含表單 html 和 javascript 來處理 ajax 調用,如下所示:

<script type="text/javascript">
$(document).ready(function() {
$( "#target" ).submit(function() {
console.log('Form was submitted');
$.ajax({
        type: "POST",
        url: "/hello/",  // or just url: "/my-url/path/"
        data: {
            query: $( "#query" ).val()   
        },
        success: function(data) {
            console.log(data);
        }
    });
return false;
  });   
  })
</script>
<form id="target" action="." method="post">{% csrf_token %}
 <input id= "query" type="text" value="Hello there">
 <input type="submit" value="Search Recent Tweets">
</form>

我應該處理 ajax 調用的views.py如下所示:

 from django.core.context_processors import csrf
 from django.shortcuts import render_to_response
 from django.template.loader import get_template
 from django.template import Context,RequestContext
 from django.views.decorators.csrf import ensure_csrf_cookie
 from django.http import HttpResponse

 # access resource
 def hello(request):
  c = {}
  c.update(csrf(request))
  if request.is_ajax():
        t = get_template('template.html')
        #html = t.render(Context({'result': 'hello world'}))
        con = RequestContext(request, {'result': 'hello world'})
        return render_to_response('template.html', c, con)
  else:
        return HttpResponse('Not working!') 

我嘗試遵循有關跨站點請求偽造保護的官方文檔,並查看了幾個解決類似問題的 stackoverflow 問題。 我在我的html模板文件中包含了{% csrf_token %}但它似乎仍然不起作用。 我在控制台中收到一條錯誤消息,提示 ajax 調用失敗:

POST http://127.0.0.1:8000/hello/ 403 (FORBIDDEN)   

如何將result變量與我的 http 響應一起傳遞並使 ajax 調用順利工作? 任何幫助深表感謝。

編輯-1

我應該沒有將csrf令牌與我的發布請求一起傳遞。 所以根據文檔,我將以下代碼添加到我的模板 javascript 中:

function 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 = jQuery.trim(cookies[i]);
        // 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;
}
var csrftoken = getCookie('csrftoken');
console.log(csrftoken);

//Ajax call
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    crossDomain: false, // obviates need for sameOrigin test
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

當我在瀏覽器中刷新模板html頁面時,我在控制台中得到null ,表明沒有設置或未定義cookie。 我錯過了什么?

因為你沒有發布csrfmiddlewaretoken ,所以 Django 禁止你。這份文件可以幫助你。

對於懶人:

首先下載cookie: http : //plugins.jquery.com/cookie/

將其添加到您的 html:

<script src="{% static 'designer/js/jquery.cookie.js' %}"></script>

現在您可以創建一個有效的 POST 請求:

var csrftoken = $.cookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

$.ajax(save_url, {
    type : 'POST',
    contentType : 'application/json',
    data : JSON.stringify(canvas),
    success: function () {
        alert("Saved!");
    }

})

如果您沒有將 js 嵌入到模板中,最快的解決方案是:

<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>在您引用模板中的 script.js 文件之前,然后將csrfmiddlewaretoken添加到您的data字典中:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

如果你確實將你的 js 嵌入到模板中,它就像: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

我在現場找到了所有以前的答案,但讓我們把事情放在上下文中。

403 禁止響應來自 CSRF 中間件(參見跨站請求偽造保護):

默認情況下,如果傳入請求未通過 CsrfViewMiddleware 執行的檢查,則會向用戶發送“403 Forbidden”響應。

許多選項可用。 我建議遵循@fivef答案,以便 jQuery 在每個帶有$.ajaxSetup AJAX 請求之前添加X-CSRFToken標頭。

這個答案需要 cookie jQuery 插件。 如果這是不可取的,另一種可能是添加:

function 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 = jQuery.trim(cookies[i]);
            // 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;
}
var csrftoken = getCookie('csrftoken');

但是:如果設置CSRF_COOKIE_HTTPONLY設置為 True,這經常發生,因為安全中間件建議如此,那么即使使用了@ensure_csrf_cookie() ,cookie 也不存在。 在這種情況下,必須以每種形式提供{% csrf_token %} ,這會產生諸如<input name="csrfmiddlewaretoken" value="cr6O9...FUXf6" type="hidden"> 所以csrfToken變量可以簡單地通過以下方式獲得:

var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();

當然,再次需要$.ajaxSetup

其他可用但不推薦的選項是使用@csrf_exempt()禁用特定表單的中間件或 csrf 保護。

data: {"csrfmiddlewaretoken" : "{{csrf_token}}"}

您看到“403 (FORBIDDEN)”,因為您沒有發送“csrfmiddlewaretoken”參數。 在模板中,每個表單都有這個:{% csrf_token %}。 您應該將“csrfmiddlewaretoken”添加到您的 ajax 數據字典中。 我的示例是將“product_code”和“csrfmiddlewaretoken”發送到應用程序“basket”視圖“remove”:

$(function(){
    $('.card-body').on('click',function(){
        $.ajax({
          type: "post",
          url: "{% url 'basket:remove'%}",
          data: {"product_code": "07316", "csrfmiddlewaretoken" : "{{csrf_token}}" }
        });
    })
});

要設置 cookie,請在您的視圖中使用ensure_csrf_cookie裝飾器:

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def hello(request):
    code_here()

確保您沒有緩存顯示表單的頁面/視圖。 它可能正在緩存您的 CSRF_TOKEN。 發生在我身上!

另一種方法是添加帶有“{{ csrf_token }}”值的 X-CSRFTOKEN 標頭,如下例所示:

$.ajax({
            url: "{% url 'register_lowresistancetyres' %}",
            type: "POST",
            headers: {//<==
                        "X-CSRFTOKEN": "{{ csrf_token }}"//<==
                },
            data: $(example_form).serialize(),
            success: function(data) {
                //Success code
            },
            error: function () {
                //Error code
            }
        });

嘗試在您的調度代碼中包含此裝飾器

from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt     
@method_decorator(csrf_exempt, name='dispatch')
def dispatch(self, request, *args, **kwargs):
     return super(LessonUploadWorkView,self).dispatch(request,*args,**kwargs)

使用SSL / HTTPS與CSRF_COOKIE_HTTPONLY =假,我還沒有csrftoken在cookie,或者使用的getCookie(名稱)中提出的功能Django的文件或提出的jquery.cookie.js fivef

Wtower摘要是完美的,我認為在從 settings.py 中刪除 CSRF_COOKIE_HTTPONLY 后它會起作用,但它不在 https 中!

為什么 csrftoken 在 document.cookie 中不可見???

而不是得到

“django_language=fr;csrftoken=rDrGI5cp98MnooPIsygWIF76vuYTkDIt”

我只得到

“django_language=fr”

為什么? 就像SSL/https 從頭中刪除 X-CSRFToken我認為這是由於 Nginx 的代理頭參數,但顯然不是......知道嗎?

django doc Notes不同,在帶有 https 的 cookie 中使用 csrf_token 似乎是不可能的。 傳遞 csrftoken 的唯一方法是通過 DOM 在 html 中使用 {% csrf_token %} 並通過使用在 jQuery 中獲取它

var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();

然后可以通過標頭( xhr.setRequestHeader )或通過params將其傳遞給 ajax。

這對我有用

模板.html

  $.ajax({
    url: "{% url 'XXXXXX' %}",
    type: 'POST',
    data: {modifica: jsonText, "csrfmiddlewaretoken" : "{{csrf_token}}"},
    traditional: true,
    dataType: 'html',
    success: function(result){
       window.location.href = "{% url 'XXX' %}";
        }
});

查看.py

def aggiornaAttivitaAssegnate(request):
    if request.is_ajax():
        richiesta = json.loads(request.POST.get('modifica'))

您必須更改文件夾 chmod 755 和文件 (.php ,.html) chmod 644。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM