jQuery 在Django中通过AJAX发布参数时“CSRF令牌丢失或不正确”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6506897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 20:58:37  来源:igfitidea点击:

"CSRF token missing or incorrect" while post parameter via AJAX in Django

djangojquerydjango-csrf

提问by brsbilgic

I try to post parameter like

我尝试发布参数,如

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

However, Django return Forbidden 403. CSRF verification failed. Request aborted.I am using 'django.middleware.csrf.CsrfViewMiddleware'and couldn't find how I can prevent this problem without compromising security.

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

回答by sigurd

You can make AJAX post request in two different ways:

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

  1. To tell your view not to check the csrf token. This can be done by using decorator @csrf_exempt, like this:

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def your_view_name(request):
        ...
    
  2. To embed a csrf token in each AJAX request, for jQuery it may be:

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

    Where the getCookiefunction retrieves csrf token from cookies. I use the following implementation:

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

    Also, jQuery has a pluginfor accessing cookies, something like that:

    // set cookie
    $.cookie('cookiename', 'cookievalue');
    // read cookie
    var myCookie = $.cookie('cookiename');
    // delete cookie
    $.cookie('cookiename', null);
    
  1. 告诉您的视图不要检查 csrf 令牌。这可以通过使用装饰器来完成@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") }
        });
    });
    

    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');
    // read cookie
    var myCookie = $.cookie('cookiename');
    // delete cookie
    $.cookie('cookiename', null);
    

回答by jerrykan

The simplest way I have found is to include the {{csrf_token}}value in the data:

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

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

回答by toto_tico

It took me a while to understand what to do with the codethat Daniel posted. But actually all you have to do is paste it at the beginning of the javascript file.

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

For me, the best solution so far is:

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

  1. Create a csrf.jsfile

  2. Paste the codein the csrf.jsfile

  3. Reference the code in the template you need it

    <script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
    
  1. 创建csrf.js文件

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

  3. 参考你需要的模板中的代码

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

Notice that STATIC_PREFIX/js/csrf.jspoints to my file. I am actually loading the STATIC_PREFIXvariable with {% get_static_prefix as STATIC_PREFIX %}.

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



Advanced tip:if you are using templates and have something like base.htmlwhere you extend from, then you can just reference the script from there and you don't have to worry anymore in there rest of your files. As far as I understand, this shouldn't represent any security issue either.

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

回答by Khaino

Simple and short

简单而简短

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

OR

或者

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

docs

文档

回答by CpILL

For lack of a straight forward answer, you just have to add the header X-CSRFTokento the ajax request which is in the cookie csrftoken. JQuery doesn't do cookies (for some reason) without a pluginso:

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

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

and the minimal code change is:

最小的代码更改是:

$.ajax({
  headers: { "X-CSRFToken": $.cookie("csrftoken") },
  ...
});

回答by jbiz

Thank you everyone for all the answers. I am using Django 1.5.1. I'm a little late to the party, but here goes.

谢谢大家的回答。我正在使用 Django 1.5.1。我参加聚会有点晚了,但我来了。

I found the link to the Django projectto be very useful, but I didn't really want to have to include the extra JavaScript code every time I wanted to make an Ajax call.

我发现Django 项目的链接非常有用,但我真的不想在每次想要进行 Ajax 调用时都包含额外的 JavaScript 代码。

I like jerrykan's response as it is very succinct and only adds one line to an otherwise normal Ajax call. In response to the comments below his comment regarding situations when Django template tags are unavailable, how about loading up the csrfmiddlewaretoken from the DOM?

我喜欢 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); } 
});

EDIT March 2016

编辑 2016 年 3 月

My approach to this issue over the past few years has changed. I add the code below (from the Django docs) to a main.js file and load it on every page. Once done, you shouldn't need to worry about the CSRF token with ajax again.

在过去的几年里,我对这个问题的态度发生了变化。我将下面的代码(来自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');

回答by bfontaine

I got the same issue yesterday and thought it would help people if there were a simple way to handle it, so I wrote a jQuery plugin for that: jquery.djangocsrf. Instead of adding the CSRF token in every request, it hooks itself on the AjaxSend jQuery event and adds the client cookie in a header.

我昨天遇到了同样的问题,并认为如果有一种简单的方法来处理它会帮助人们,所以我为此编写了一个 jQuery 插件:jquery.djanocsrf。它不是在每个请求中都添加 CSRF 令牌,而是将自己挂在 AjaxSend jQuery 事件上,并在标头中添加客户端 cookie。

Here's how to use it:

以下是如何使用它:

1- include it:

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- enable it in your code:

2- 在您的代码中启用它:

$.djangocsrf( "enable" );

Django always add the token in a cookie if your template uses {% csrf_token %}. To ensure it always adds it even if you don't use the special tag in your template, use the @ensure_csrf_cookiedecorator:

如果您的模板使用{% 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')

Note: I'm using Django 1.6.2.

注意:我使用的是 Django 1.6.2。

回答by Hasan Ramezani

Include x-csrftokenheader in request:

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

});

回答by Marek ?idek

The fastest solution without any plugins if you are not embedding js into your template is:

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

Put <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>before your reference to script.js file in your template, then add csrfmiddlewaretokeninto your datadictionary:

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

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

If you do embed your js into the template, it's as simple as: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

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

回答by Fr333du

If, after reading other answers, someone is still struggling please try this:

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

   $.ajax({
            type: "POST",
            beforeSend: function (request)
            {
                request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
            },
            url: servlet_path,
            data : data,
            success : function(result) {
            console.log("Success!");
   }
});