如何在 AJAX 中传递 Django csrf 令牌(没有 jQuery)

Posted

技术标签:

【中文标题】如何在 AJAX 中传递 Django csrf 令牌(没有 jQuery)【英文标题】:How to pass Django csrf token in AJAX (without jQuery) 【发布时间】:2016-08-19 01:15:23 【问题描述】:

基于w3schools ajax example,我正在尝试进行删除调用,然后从表中删除相应的行。这里有很多关于如何使用 JQuery 的答案,但我没有这样做。我找到了this answer,它让我这样写我的 javascript

function deleteFullLicense(rowid, objectid) 
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() 
      if (xhttp.readyState == 4 && xhttp.status == 204) 
        row = document.getElementById(rowid);
        row.parentNode.removeChild(row);
      
      else 
        window.alert("Something went wrong. The delete failed.");
      
    ;
    xhttp.open("POST", "deleteLicense/" + objectid, true);
    xhttp.send('csrfmiddlewaretoken': ' csrf_token ');

但我收到了Forbidden (CSRF token missing or incorrect.) 消息。我应该如何发送令牌?

【问题讨论】:

你需要将is设置为header。也许这可以帮助你:***.com/questions/22063612/… 我尝试将其设置为标题使用:xhttp.setRequestHeader("csrfmiddlewaretoken", ' csrf_token ') 但这没有区别。还有什么需要做的吗? 【参考方案1】:

事实证明,如果我将其命名为 X-CSRFToken,它就会起作用。发现了它here if you want to read more。

function deleteFullLicense(rowid, objectid) 
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() 
      if (xhttp.readyState == 4 && xhttp.status == 204) 
        row = document.getElementById(rowid);
        row.parentNode.removeChild(row);
      
    ;
    xhttp.open("POST", "deleteLicense/" + objectid, true);
    xhttp.setRequestHeader("X-CSRFToken", ' csrf_token ')
    xhttp.send();

【讨论】:

【参考方案2】:

标头名称X-CSRFToken实际上来自Django settings.py中的参数CSRF_HEADER_NAME。当接收到前端请求(例如 ajax 调用)时,Django 内部会检查头参数并将X-CSRFToken 转换为HTTP_X_CSRFTOKEN,这是CSRF_HEADER_NAME 的默认值。

更好的方法是:

转换CSRF_HEADER_NAME的值 将上一步转换后的值渲染到 html 模板中 在前端代码(例如 HTML 模板或单独的 js 文件)中,使用该值和 CSRF 令牌在每个 ajax 调用上创建自定义标头以提交表单。

这是一个简单的例子

settings.py

CSRF_HEADER_NAME = "HTTP_ANTI_CSRF_TOKEN"

views.py的视图函数中

from django.conf import settings
from django.http.request import HttpHeaders

prefix =  HttpHeaders.HTTP_PREFIX
converted = settings.CSRF_HEADER_NAME[len(prefix):]
converted = converted.replace('_','-')
# so the value HTTP_ANTI_CSRF_TOKEN is converted to ANTI-CSRF-TOKEN,
return Response(context='custom_csrf_header_name':converted)

在您的 HTML 模板中(不是好习惯,因为这只是简单的示例)

<script>
// Note that the value is 'ANTI-CSRF-TOKEN'. when this header name goes to
// backend server, Django will internally convert it back to 'HTTP_ANTI_CSRF_TOKEN'
var custom_csrf_header_name = " custom_csrf_header_name ";

// the ajax part is almost the same as described in the accepted answer
...
xhttp.setRequestHeader(custom_csrf_header_name, ' csrf_token ')
...
</script>

【讨论】:

以上是关于如何在 AJAX 中传递 Django csrf 令牌(没有 jQuery)的主要内容,如果未能解决你的问题,请参考以下文章

如何在表单的 AJAX 发布请求中传递 CSRF 令牌?

Django 如何让ajax的POST方法带上CSRF令牌

如何在Django使用ajax的POST

如何将 POST 数据中的 CSRF 令牌传递给 Django?

在 django 中使用 ajax 表单发布 csrf 令牌的这种方法有啥问题?

带有 django 的 JQuery AJAX 获取 csrf 错误 403