在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发布请求:
-
告诉你的视图不要检查csrf标记。 这可以通过使用装饰器
@csrf_exempt
来完成,如下所示:from django.views.decorators.csrf import csrf_exempt @csrf_exempt def your_view_name(request): ...
-
要在每个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是:
-
创build一个
csrf.js
文件 -
将代码粘贴到
csrf.js
文件中 -
引用您需要的模板中的代码
<script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
注意STATIC_PREFIX/js/csrf.js
指向我的文件。 我实际上是加载STATIC_PREFIX
variables与{% 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!"); } });