在Django中通过AJAX发布参数时,“CSRF令牌丢失或不正确”

我尝试发布参数

jQuery.ajax( { 'type': 'POST', 'url': url, 'contentType': 'application/json', 'data': "{content:'xxx'}", 'dataType': 'json', 'success': rateReviewResult } ); 

但是,Django返回Forbidden 403. CSRF verification failed. Request aborted. Forbidden 403. CSRF verification failed. Request aborted. 我正在使用'django.middleware.csrf.CsrfViewMiddleware'并找不到如何防止这个问题,而不会影响安全性。

您可以通过两种不同的方式发出AJAX发布请求:

  1. 告诉你的视图不要检查csrf标记。 这可以通过使用装饰器@csrf_exempt来完成,如下所示:

     from django.views.decorators.csrf import csrf_exempt @csrf_exempt def your_view_name(request): ... 
  2. 要在每个AJAX请求中embedded一个csrf标记,对于jQuery,可能是:

     $(function () { $.ajaxSetup({ headers: { "X-CSRFToken": getCookie("csrftoken") } }); }); 

    getCookie函数从cookie中获取csrf标记。 我使用下面的实现:

     function getCookie(c_name) { if (document.cookie.length > 0) { c_start = document.cookie.indexOf(c_name + "="); if (c_start != -1) { c_start = c_start + c_name.length + 1; c_end = document.cookie.indexOf(";", c_start); if (c_end == -1) c_end = document.cookie.length; return unescape(document.cookie.substring(c_start,c_end)); } } return ""; } 

    此外,jQuery 有一个访问cookie 的插件 ,就像这样:

     // set cookie $.cookie('cookiename', 'cookievalue');<br> // read cookie var myCookie = $.cookie('cookiename');<br> // delete cookie $.cookie('cookiename', null); 

我发现最简单的方法是在数据中包含{{csrf_token}}值:

 jQuery.ajax( { 'type': 'POST', 'url': url, 'contentType': 'application/json', 'data': { 'content': 'xxx', 'csrfmiddlewaretoken': '{{ csrf_token }}', }, 'dataType': 'json', 'success': rateReviewResult } ); 

我花了一段时间才明白如何处理Daniel发布的代码 。 但实际上你所要做的就是把它粘贴到JavaScript文件的开头。

对我而言,迄今为止最好的解决scheme是:

  1. 创build一个csrf.js文件

  2. 将代码粘贴到csrf.js文件中

  3. 引用您需要的模板中的代码

     <script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script> 

注意STATIC_PREFIX/js/csrf.js指向我的文件。 我实际上是加载STATIC_PREFIXvariables与{% get_static_prefix as STATIC_PREFIX %}


高级技巧:如果您使用的是模板,并且有类似base.html地方,那么您可以直接引用该脚本,而不必担心其他文件。 据我了解,这也不应该代表任何安全问题。

我昨天得到了同样的问题,并认为它会帮助人们,如果有一个简单的方法来处理它,所以我写了一个jQuery插件: jquery.djangocsrf 。 它不是在每个请求中添加CSRF标记,而是将其自身绑定在AjaxSend jQuery事件上,并将客户端Cookie添加到标头中。

以下是如何使用它:

1-包括它:

 <script src="path/to/jquery.js"></script> <script src="path/to/jquery.cookie.js"></script> <script src="path/to/jquery.djangocsrf.js"></script> 

2-在你的代码中启用它:

 $.djangocsrf( "enable" ); 

如果您的模板使用{% csrf_token %}则Django总是将该标记添加到cookie中。 为了确保即使不在模板中使用特殊标签,也要始终添加它,请使用@ensure_csrf_cookie装饰器:

 from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def my_view(request): return render(request, 'mytemplate.html') 

注意:我正在使用Django 1.6.2。

谢谢大家的所有答案。 我正在使用Django 1.5.1。 我晚了一点晚了,但这里。

我发现Django项目的链接非常有用,但是我并不想每次想要进行Ajax调用时都要包含额外的JavaScript代码。

我喜欢jerrykan的回应,因为它非常简洁,只增加了一行,以正常的Ajax调用。 为了回应下面关于Django模板标签不可用时的情况的评论,如何从DOM中加载csrfmiddlewaretoken?

 var token = $('input[name="csrfmiddlewaretoken"]').prop('value'); jQuery.ajax({ type: 'POST', url: url, data: { 'csrfmiddlewaretoken': token }, dataType: 'json', success: function(data) { console.log('Yippee! ' + data); } }); 

编辑2016年3月

过去几年我对这个问题的看法已经改变了。 我将下面的代码(从Django文档 )添加到main.js文件并将其加载到每个页面上。 完成之后,您不必再担心使用ajax的CSRF令牌。

 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'); 

在请求中包含x-csrftoken标头:

 var token = $('input[name="csrfmiddlewaretoken"]').prop('value'); jQuery.ajax({ type: 'POST', url: url, beforeSend : function(jqXHR, settings) { jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie()); }, data: data, dataType: 'json', }); 

由于缺乏简单的答案,只需将头部X-CSRFToken添加到cookie csrftoken的ajax请求csrftoken 。 JQuery不会做cookies(出于某种原因)没有插件如此:

 <script src="ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> 

最小的代码变化是:

 $.ajax({ headers: { "X-CSRFToken": $.cookie("csrftoken") }, ... }); 

如果在阅读其他答案之后,有人仍然在努力尝试:

  $.ajax({ type: "POST", beforeSend: function (request) { request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}"); }, url: servlet_path, data : data, success : function(result) { console.log("Success!"); } });