使用JS / Ajax API将通知标记为已读

时间:2017-05-05 19:23:58

标签: javascript ajax django notifications csrf

我在我的网站中实现了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丢失在哪里,我还是有点失落。

2 个答案:

答案 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函数,这就是诀窍。