Ошибка CSRF Django ajax .post без формы

По этой теме есть много вопросов о переполнении стека, которые я просматривал и не нашел то, что ищу, но прошу прощения, если это повторение другого вопроса.

Моя проблема в том, что я считаю, что правильно настроил файлы cookie CSRF для своего проекта django, но получаю следующую ошибку (которая требует отличия):

Запрещено (403)

Ошибка проверки CSRF. Запрос прерван. Помощь

Причина отказа:

CSRF token missing or incorrect.

Используя firebug, я могу проверить, что я получаю токен csrf с моего сервера, и что мой .post включает тот же токен csrf в запрос. Я знаю, что проблема не в моем браузере, потому что я могу просмотреть файлы cookie своего браузера и убедиться, что тот же токен csrf хранится в браузере.

views.py:

from django.views.decorators.csrf import ensure_csrf_cookie, csrf_exempt
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.template import RequestContext

def base_view(request):
    #Determine data for page

    return render_to_response('template.html',{'important_data':important_data}, context_instance=RequestContext(request))

@login_required
def ajax_view(request):
    if request.method == u'POST':
        #Do some things with database
        return HttpResponse('')

template.html

<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script>
<script src="{{ STATIC_URL }}JS/jquery.js"></script>
</head>
<body>
{% csrf_token %}
<div class="ajax_trigger"></div>
</body>
</html>

jquery.js

$(document).ready(function(){
    $(".ajax_trigger").click(function(){
            $.post("http://127.0.0.1:8000/ajax",{data:"test"},function(){},'json'); 
    });
});

//code recommended at https://docs.djangoproject.com/en/dev/ref/contrib/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');

function csrfSafeMethod(method) {
    //these HTTP methods do not require CSRF protection
    return(/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
    // test that a given url is a same-origin URL
    // url could be relative or scheme relative or absolute
    var host = document.location.host; // host + port
    var protocol = document.location.protocol;
    var sr_origin = '//' + host;
    var origin = protocol + sr_origin;
    //Allow absolute or scheme relative URLs to the same origin
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
    // or any other URL that isn't scheme relative or absolute i.e relative
    !(/^(\/\/|http:|https:).*/.test(url));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
            //send the token to same-origin, relative URLs only.
            //send the token only if the method warrants CSRF protection
            //using the CSRFToken value acquired earlier
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

settings.py фрагмент:

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

Если я добавлю @csrf_exempt в свой ajax_view, то ответ на почтовый запрос будет успешным. Но разве это не противоречит цели защиты от csrf в первую очередь?

Я не думаю, что проверка CSRF Django завершилась ошибкой с помощью Ajax POST request содержит ответ, который я ищу, потому что, похоже, он применим только к старой версии django.

Спасибо всем, кто может помочь мне указать в правильном направлении!

ОБНОВЛЕНИЕ: эта конфигурация работала на django 1.4, но на django 1.5+ у меня возникли некоторые проблемы. После ознакомления с примечаниями к выпуску Django 1.5 (https://docs.djangoproject.com/en/dev/releases/1.5/#miscellaneous) Я обнаружил следующее: «Тег шаблона csrf_token больше не заключен в div. Если вам нужна проверка HTML по сравнению со строгими DTD до HTML5, вы должны добавить div вокруг него на ваших страницах ". Это что-нибудь значит для кого-нибудь? Кроме того, я заметил в документации django (https://docs.djangoproject.com/en/dev/ref/contrib/csrf/), что для ситуации, подобной моей, когда страница использует ajax без формы, решение состоит в том, чтобы «использовать sure_csrf_cookie () в представлении, которое отправляет страницу». Я пробовал это, но разницы не заметил.

Если кто-то все еще читает это, спасибо.

ОБНОВЛЕНИЕ 2: Мне будет очень неловко, если кто-то обнаружит ошибку в моих URL-адресах всех вещей. Возможно, придется зарегистрироваться на djangocon с вымышленным именем или что-то в этом роде ...

urls.py

from django.conf.urls import patterns, include, url
from mysite.views import *


# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url('^$', base_view, {'category' : 'general'}, name='home'),
    url('^ajax$', ajax_view),

    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
)

person johnmic07    schedule 20.03.2014    source источник
comment
Похоже, ваш URL-адрес POST отличается от того, откуда вы получили csrftoken. Это может привести к неверному токену.   -  person Rohan    schedule 20.03.2014
comment
URL моего сообщения - 127.0.0.1:8000/ajax, и я получаю токен csrf от 127.0.0.1 : 8000. Я согласен с тем, что URL-адреса разные, но почему это делает токен недействительным? У вас есть ссылки на дополнительные ресурсы, объясняющие, почему это необходимо?   -  person johnmic07    schedule 20.03.2014


Ответы (1)


попробуйте добавить декоратор sure_csrf_cookie

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def ajax_view(request):

и вам не нужен {% csrf_token%} в template.html

person privaloff    schedule 23.03.2014
comment
Вы были правы, что мне не нужен был тег шаблона csrf (я думаю, он нужен только для форм, когда я думаю об этом), но мне все еще не повезло с этим. Думаю, мне придется подождать djangocon 2014 lol - person johnmic07; 24.03.2014
comment
Можете ли вы опубликовать свой файл URL-адресов? - person privaloff; 24.03.2014
comment
мои URL-адреса сейчас открыты. Надеюсь, это поможет. - person johnmic07; 25.03.2014
comment
как ни странно, но ваш код работает нормально, я меняю только несколько вещей, `$ (. ajax_trigger) .click (function () {$ .post (/ ajax /, {data: test}, function () {}, 'json'); `также отсутствует **)}: ** в конце файла jquery.js - person privaloff; 25.03.2014
comment
Концевые скобки были опечаткой. В фактическом коде я не упустил их, но это хороший улов;) Что касается URL-адреса сообщения, мне, к сожалению, не повезло с вашим изменением. Что интересно, когда я изменяю http: / full_url на / ajax /, я получаю ошибку CSRF даже при использовании @CSRF_exempt в представлении. Мне интересно, может быть, проблема в моем браузере или в чем-то еще, внешнем по отношению к Django. - person johnmic07; 30.03.2014