1. 程式人生 > 其它 >django 使用ajax請求 Forbidden (CSRF token missing or incorrect.)

django 使用ajax請求 Forbidden (CSRF token missing or incorrect.)

技術標籤:學習筆記pythonjavascriptdjango

django-ajax請求

前言

django框架預設繼承了防CSRF(英文:Cross-site request forgery)攻擊的中介軟體,也就是每次頁面請求都會隨機生成一個符串又稱CSRF_TOKEN,這是一個很實用的功能,推薦開啟,但是開啟此中介軟體,如果不在請求(POST)裡附帶CSRF_TOKEN值,請求就會被攔截掉。初次接觸時,上網看了很多解決方案都不太正確,特此整理一下。

一、解決方案

ajax請求

1.ajax全域性設定

在當前頁面body標籤結束前加

<script type="text/javascript"
> var token = "{{ csrf_token }}" $.ajaxSetup({ headers: { 'X-CSRFTOKEN': `${token}` }, // 這裡是headers,不是data }); </script>

這部是通過$.ajaxSetup()設定全域性ajax的請求頭,在請求頭中加入了一個鍵值對
{ 'X-CSRFTOKEN': '{{ CSRF_TOKEN }}'} 後面就可以正常的進行請求。例:

    $.ajax({
        type: "POST"
, url: "action", contentType: "application/json", data: {}, success: function(r) { alert(r) } })

2.直接加在ajax請求體裡

    $.ajax({
        type: "POST",
        url: "action",
        headers: { 'X-CSRFTOKEN': `
${token}`
}, contentType: "application/json", data: {}, success: function(r) { alert(r) } })

二、原理

直接看原始碼

if request.method == "POST":
    try:
        request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
    except OSError:
        # Handle a broken connection before we've completed reading
        # the POST data. process_view shouldn't raise any
        # exceptions, so we'll ignore and serve the user a 403
        # (assuming they're still listening, which they probably
        # aren't because of the error).
        pass

if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

request_csrf_token = _sanitize_token(request_csrf_token)
if not _compare_masked_tokens(request_csrf_token, csrf_token):
    return self._reject(request, REASON_BAD_TOKEN)

當POST請求發生時, 會先通過 request.POST.get('csrfmiddlewaretoken', '') 方法來獲取 token網上的很多解決方案的是推薦在 ajax請求體data引數中加入token值,然而這個方法只能獲取表單請求,所以此處get不到值,返回空。被拒絕訪問並彈出錯誤:
Forbidden (CSRF token missing or incorrect.)

而原始碼在表單請求get token失敗後還會做一段處理,就是檢查請求頭,request.META.get(settings.CSRF_HEADER_NAME, ''),所以就有了前面的解決方案,在請求頭中加入 { 'X-CSRFTOKEN': '{{ CSRF_TOKEN }}'} 。而且註釋也很清楚的說明了

Fall back to X-CSRFToken, to make things easier for AJAX,
and possible for PUT/DELETE.

這個方法是為了ajax專門簡化的。對應django版本 3.x