76

我尝试发布参数

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

Forbidden 403. CSRF verification failed. Request aborted. 但是,我正在使用Django 返回'django.middleware.csrf.CsrfViewMiddleware',但找不到如何在不影响安全性的情况下防止此问题。

4

13 回答 13

115

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

  1. 告诉您的观点不要检查 csrf 令牌。这可以通过使用 decorator 来完成@csrf_exempt,如下所示:

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

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

    函数从 cookie 中检索csrfgetCookie令牌的位置。我使用以下实现:

    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');
    // read cookie
    var myCookie = $.cookie('cookiename');
    // delete cookie
    $.cookie('cookiename', null);
    
于 2011-06-30T10:42:07.473 回答
55

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

jQuery.ajax(
    {
        'type': 'POST',
        'url': url,
        'contentType': 'application/json',
        'data': {
            'content': 'xxx',
            'csrfmiddlewaretoken': '{{ csrf_token }}',
        },
        'dataType': 'json',
        'success': rateReviewResult 
    }
);
于 2011-07-29T04:10:08.110 回答
25

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

对我来说,到目前为止最好的解决方案是:

  1. 创建csrf.js文件

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

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

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

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


高级提示:如果您使用模板并且有类似base.html从哪里扩展的东西,那么您可以从那里引用脚本,您不必再担心其他文件。据我了解,这也不应该代表任何安全问题。

于 2012-04-30T15:29:18.593 回答
17

简单而简短

$.ajaxSetup({
  headers: { "X-CSRFToken": '{{csrf_token}}' }
});

或者

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", '{{csrf_token}}');
    }
  }
});

文档

于 2017-11-19T09:55:57.063 回答
9

由于缺乏直截了当的答案,您只需将标头添加X-CSRFToken到 cookie 中的 ajax 请求中csrftokenJQuery 在没有插件的情况下不会做 cookie(出于某种原因),所以:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

最小的代码更改是:

$.ajax({
  headers: { "X-CSRFToken": $.cookie("csrftoken") },
  ...
});
于 2017-02-16T21:55:03.650 回答
5

如果您没有将 js 嵌入到模板中,那么没有任何插件的最快解决方案是:

在您的模板中对 script.js 文件的引用之前放置<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>,然后添加csrfmiddlewaretoken到您的data字典中:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

如果你确实将你的 js 嵌入到模板中,它很简单:data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

于 2018-08-09T12:28:10.957 回答
4

我昨天遇到了同样的问题,并认为如果有一种简单的方法来处理它会对人们有所帮助,所以我为此编写了一个 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 %}. 为了确保即使您没有在模板中使用特殊标签,它也始终添加它,请使用@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。

于 2014-03-21T11:32:35.017 回答
4

谢谢大家的所有答案。我正在使用 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');

于 2013-06-13T04:02:41.663 回答
4

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',

});
于 2016-04-10T19:53:21.680 回答
0

html

<form action="">
        {% csrf_token %}
    </form>

JS

 <script>   
     const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
              const request = new Request(
                   'url_here',
                  {headers: {'X-CSRFToken': csrftoken}}
              );
              fetch(request, {
                  method: 'POST',
                  // mode: 'same-origin' optinal // Do not send CSRF token to another domain.
              }).then(function(response) {
                  console.log(response);
              });
    
    </script>

更多详细信息参考链接

于 2021-11-23T09:32:05.430 回答
0

请不要在这样做时确保您没有标签{% csrf_token %}内部。<form></form>然后如解释here将以下代码添加到您的javascript

    function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // 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;
    }
    const csrftoken = getCookie('csrftoken');

// using js fetch
// https://docs.djangoproject.com/en/3.1/ref/csrf/#setting-the-token-on-the-ajax-request
    const request = new Request(
    /* URL */,
    {headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
    method: 'POST',
    mode: 'same-origin'  // Do not send CSRF token to another domain.
}).then(function(response) {
    // ...
});
于 2020-11-12T17:06:45.623 回答
0

只是想把它放在这里,如果GET在你的用例中工作,那么它就不需要 CSRF 令牌。对于我的用例,使用GET没问题。

于 2021-09-03T05:06:51.933 回答
0

如果在阅读其他答案后,有人仍在苦苦挣扎,请尝试以下操作:

   $.ajax({
            type: "POST",
            beforeSend: function (request)
            {
                request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
            },
            url: servlet_path,
            data : data,
            success : function(result) {
            console.log("Success!");
   }
});
于 2016-09-07T11:17:40.430 回答