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