我在我的网站中实现了django-notifications,并且工作得很好(https://github.com/django-notifications/django-notifications)。 唯一的,我希望我得到的最后一个问题是通知永远不会被标记为已读。有可能通过API调用来完成它,所以我在JS中写了一些东西。我能够获取数据,但我无法更改/ POST它们,因为我总是得到403.我可以检查/取消选中Admin-Page中的布尔值,但我不能使用API调用。有没有人知道我能做什么? “文档”只是Github上的一个站点。制作者只做了一些简短的例子而没有很多Context。
我的代码:
$(".notiBla").click(function(){
$.ajax({
url:("/inbox/notifications/api/unread_list/?max=3&mark_as_read=false/"),
dataType:'json',
type: 'POST',
data: "unread_list",
success:function(response){
response.unread_list[0].unread=false
console.log(response.unread_list[0].unread)
}
});
});
这会返回403因为我不允许进行POST。当我使用Get时它会正确显示数据,但这是无用的,因为我需要更改数据... 有人知道答案或其他方式来实现我的目标吗?
好的,我刚刚发现了一条错误消息。它说:
Forbidden (CSRF token missing or incorrect.): /inbox/notifications/api/unread_list/
[05/May/2017 19:38:28] "POST /inbox/notifications/api/unread_list/?max=3&mark_as_read=false/ HTTP/1.1" 403 2502
但由于我不知道CSRF丢失在哪里,我还是有点失落。
答案 0 :(得分:1)
要对Django视图进行Ajax POST,您需要传递一个CSRF令牌:将此键添加到.ajax()对象:
csrfmiddlewaretoken: "{{ csrf_token }}",
Django的{{ csrf_token }}
模板变量将输出一个令牌字符串,例如"mytoken123456789"
。不要与{% csrf_token %}
元素内的模板标记<form>
混淆,后者输出HTML输入元素:
<input type="hidden" name='csrfmiddlewaretoken' value='mytoken123456789' />
答案 1 :(得分:1)
来自文档:
AJAX¶
虽然上述方法可用于AJAX POST请求,但它有一些不便之处:您必须记住每次POST请求都将CSRF令牌作为POST数据传递。因此,有一种替代方法:在每个XMLHttpRequest上,将自定义X-CSRFToken标头设置为CSRF标记的值。这通常更容易,因为许多JavaScript框架提供了允许在每个请求上设置标头的钩子。
首先,您必须获得CSRF令牌。如何做到这取决于是否启用了CSRF_USE_SESSIONS设置。
如果CSRF_USE_SESSIONS为False,则获取令牌¶
令牌的推荐来源是csrftoken cookie,如果您已按照上述方式为视图启用了CSRF保护,则会设置该cookie。
请注意
默认情况下,CSRF令牌cookie名为csrftoken,但您可以通过CSRF_COOKIE_NAME设置控制Cookie名称。
默认情况下,CSRF标头名称为HTTP_X_CSRFTOKEN,但您可以使用CSRF_HEADER_NAME设置对其进行自定义。 获取令牌非常简单:
// using jQuery
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');
使用JavaScript Cookie库替换getCookie可以简化上面的代码:
var csrftoken = Cookies.get('csrftoken');
请注意
CSRF令牌也存在于DOM中,但只有在模板中使用csrf_token明确包含时才会出现。 cookie包含规范令牌; CsrfViewMiddleware更喜欢cookie到DOM中的令牌。无论如何,如果令牌存在于DOM中,您将保证拥有cookie,因此您应该使用cookie! 警告
如果您的视图没有呈现包含csrf_token模板标记的模板,Django可能不会设置CSRF令牌cookie。这在表单动态添加到页面的情况下很常见。为了解决这种情况,Django提供了一个视图装饰器来强制设置cookie:ensure_csrf_cookie()。 如果CSRF_USE_SESSIONS为True,则获取令牌¶
如果激活CSRF_USE_SESSIONS,则必须在HTML中包含CSRF令牌,并使用JavaScript从DOM读取令牌:
{% csrf_token %}
<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
</script>
在AJAX请求中设置令牌¶
最后,您必须在AJAX请求中实际设置标头,同时使用jQuery 1.5.1及更高版本中的settings.crossDomain保护CSRF令牌不被发送到其他域:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
简单地说,只需在js文件中提供getCookie函数并设置csrftoken变量。 然后添加ajaxSetup函数,这就是诀窍。