如何在AJAX中传递Django csrf令牌(不带jQuery)

时间:2016-04-25 14:54:13

标签: javascript ajax django

基于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.)消息。我该如何发送令牌?

2 个答案:

答案 0 :(得分: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();
}

答案 1 :(得分:1)

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

更好的方法是:

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

这是一个简单的示例

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>