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

做~自己de王妃 提交于 2019-11-26 11:43:26
sigurd

You can make AJAX post request in two different ways:

  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 getCookie function 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 plugin for accessing cookies, something like that:

    // set cookie
    $.cookie('cookiename', 'cookievalue');
    // read cookie
    var myCookie = $.cookie('cookiename');
    // delete cookie
    $.cookie('cookiename', null);
    
jerrykan

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

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

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

For me, the best solution so far is:

  1. Create a csrf.js file

  2. Paste the code in the csrf.js file

  3. Reference the code in the template you need it

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

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


Advanced tip: if you are using templates and have something like base.html where 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.

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

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.

Here’s how to use it:

1- include it:

<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:

$.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_cookie decorator:

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.

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.

I found the link to the Django project to 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.

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?

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

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.

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

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

<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") },
  ...
});

Include x-csrftoken header in request:

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

});

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

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

$.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 }}'}

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!");
   }
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!