«Токен CSRF отсутствует или неверен» при публикации параметра через AJAX в Django - PullRequest
55 голосов
/ 28 июня 2011

Я пытаюсь опубликовать параметр как

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

Тем не менее, Джанго возвращается Forbidden 403. CSRF verification failed. Request aborted. Я использую 'django.middleware.csrf.CsrfViewMiddleware' и не могу найти, как я могу предотвратить эту проблему, не ставя под угрозу безопасность.

Ответы [ 10 ]

85 голосов
/ 30 июня 2011

Вы можете сделать AJAX-запрос двумя разными способами:

  1. Чтобы ваш взгляд не проверял токен csrf. Это можно сделать с помощью декоратора @csrf_exempt, например:

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def your_view_name(request):
        ...
    
  2. Чтобы вставить токен csrf в каждый запрос AJAX, для jQuery это может быть:

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

    Где функция getCookie получает токен csrf из файлов cookie. Я использую следующую реализацию:

    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);
    
38 голосов
/ 29 июля 2011

Самый простой способ, который я нашел, это включить значение {{csrf_token}} в данные:

jQuery.ajax(
    {
        'type': 'POST',
        'url': url,
        'contentType': 'application/json',
        'data': {
            'content': 'xxx',
            'csrfmiddlewaretoken': '{{ csrf_token }}',
        },
        'dataType': 'json',
        'success': rateReviewResult 
    }
);
22 голосов
/ 30 апреля 2012

Мне потребовалось некоторое время, чтобы понять, что делать с кодом , который опубликовал Дэниел. Но на самом деле все, что вам нужно сделать, это вставить его в начало файла 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, откуда вы расширяетесь, тогда вы можете просто ссылаться на сценарий оттуда, и вам больше не придется беспокоиться об остальных из ваших файлов. Насколько я понимаю, это также не должно представлять проблему безопасности.

9 голосов
/ 19 ноября 2017

Простой и короткий

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

документы

4 голосов
/ 17 февраля 2017

В случае отсутствия прямого ответа, вам просто нужно добавить заголовок X-CSRFToken к запросу ajax, который находится в файле cookie csrftoken.JQuery не делает куки (по некоторым причинам) без плагина , поэтому:

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

и минимальное изменение кода:

$.ajax({
  headers: { "X-CSRFToken": $.cookie("csrftoken") },
  ...
});
4 голосов
/ 21 марта 2014

Вчера у меня возникла та же проблема, и я подумал, что она поможет людям, если есть простой способ ее решения, поэтому я написал для этого плагин 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" );

Django всегда добавляет токен в куки, если ваш шаблон использует {% 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.

4 голосов
/ 13 июня 2013

Спасибо всем за все ответы. Я использую Django 1.5.1. Я немного опоздал на вечеринку, но здесь идет.

Я нашел ссылку на проект Django очень полезной, но мне не хотелось включать дополнительный код JavaScript каждый раз, когда я хотел сделать Ajax-вызов.

Мне нравится ответ Джеррикана, так как он очень лаконичен и добавляет только одну строку к обычному Ajax-вызову. В ответ на комментарии ниже его комментария относительно ситуаций, когда теги шаблона Django недоступны, как насчет загрузки csrfmiddlewaretoken из 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); } 
});

РЕДАКТИРОВАТЬ март 2016

Мой подход к этому вопросу за последние несколько лет изменился. Я добавляю приведенный ниже код (из Django docs ) в файл main.js и загружаю его на каждую страницу. После этого вам больше не нужно беспокоиться о токене CSRF с ajax.

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');
3 голосов
/ 10 апреля 2016

Включить 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',

});
2 голосов
/ 09 августа 2018

Самое быстрое решение без каких-либо плагинов, если вы не встраиваете js в шаблон:

Поместите <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!");
            }
        })

Если вы вставляете свои js в шаблон, это так просто: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}

0 голосов
/ 07 сентября 2016

Если после прочтения других ответов кто-то все еще испытывает трудности, попробуйте следующее:

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