【问题标题】:How to return new csrf token at ajax POST in Django?如何在 Django 的 ajax POST 中返回新的 csrf 令牌?
【发布时间】:2016-01-02 09:49:00
【问题描述】:

我有一个简单的 Like 按钮,与 @csrf_exempt 一起使用时效果很好:

模板

<p id="like_count"> {{ topic.likes }}</p> 
<span data-type="topic" title="Like">       {% csrf_token %}
 <i class="fa fa-thumbs-up" id="liket" name="{{topic.id}}">  

阿贾克斯

$(function(){
$('#liket').click(function(){
      $.ajax({
               type: "POST",
               url: "/like/",
               data: {
               'topic_id': $(this).attr('name'), 
               'csrfmiddlewaretoken': '{{csrf_token}}'
               },
               success: tlikeSuccess,
               dataType: 'html'               
                });
    });

});
function tlikeSuccess(data, textStatus, jqXHR)
{
    $('#like_count').html(data);
}

和观点:

#@csrf_exempt 
def topic_like(request):

    args = {}
    if request.method == 'POST':

        user = request.POST.get('user')
        lu= request.user #User.objects.get(username= user)
        topic_id = int(request.POST.get('topic_id'))

        try:
            liked_topic = Topic.objects.get(id = topic_id)
        except:
            liked_topic = None  

        if TopicLike.objects.filter(liker=request.user.id, topic=topic_id).exists():

            liked_topic.likes -=1
            liked_topic.save()
            TopicLike.objects.filter(topic=topic_id, liker=request.user.id).delete()

        else:            
            liked_topic.likes +=1
            liked_topic.save()
            newliker = TopicLike(topic=topic_id, liker=request.user.id)
            newliker.save()          


    #args.update(csrf(request))
    args['likes'] = str(liked_topic.likes)
    return render(request, 'ajax_like.html', args)  

但是我不喜欢这种忽略 CSRF 的解决方法,因为它可能容易受到攻击。 另一方面,我无法将新的 CSRF 令牌返回到模板,因此我感谢您将 CSRF 集成到此按钮中的提示。

【问题讨论】:

  • Django docs 建议在标题中而不是在帖子数据中提供 csrf 令牌。
  • @Alasdair 请给我一个完整的答案。我不知道如何应用文档的建议。
  • 我认为文档很清楚。你尝试了什么?你认为缺少什么?你不明白哪一部分?

标签: ajax django django-templates django-csrf


【解决方案1】:

Django 在其docs 中已定义实际设置 AJAX 请求的标头,同时在 jQuery 1.5.1 及更高版本中使用settings.crossDomain 保护 CSRF 令牌不被发送到其他域。

获取令牌:

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

在头部设置 CSRFToken:

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

也可以试试这个方法在SO link.给出的每个AJAX请求中嵌入CSRF令牌

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

【讨论】:

  • 我将这些函数添加到我的 ajax 文件中,并在我看来删除了@csrf_exempt ,但我在领事Uncaught ReferenceError: csrftoken is not defined 中收到此错误。有什么想法吗?
  • 对不起,我很困惑。你的意思是我应该将上面的所有 3 个函数添加到我的 ajax.js 中而不改变我原来的 ajax 函数和视图?
  • 只是前 2 个方法,last(3rd) 函数是第 2 个函数的替代方法。
  • 当我将上面的 2 个函数添加到我的 ajax.js 时,无论我是否在视图中更新 CSRF,我都会得到 403 (FORBIDDEN)。 (不是我没有对我原来的 ajax 函数做任何改变。我应该有吗?)
  • 这两个函数在官方文档中定义了如何在请求中添加 csrftoken。如果您遵循了确切的程序,请检查docs
【解决方案2】:

您可以使用 javascript 手动添加 csrf 令牌。

https://docs.djangoproject.com/en/1.8/ref/csrf/#ajax

【讨论】:

  • 您能否详细说明在我的特殊情况下如何手动生成 csrf?
猜你喜欢
  • 2018-02-10
  • 2014-03-19
  • 2019-01-13
  • 2018-09-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 2015-10-02
  • 2016-08-19
相关资源
最近更新 更多