CSRF错误Django ajax .post没有形式

关于这个主题有很多堆栈溢出问题,我一直在经历并且没有找到我正在寻找的东西但是如果这是另一个问题的重复,我会道歉 .

我的问题是我相信我已经为我的django项目正确设置了CSRF cookie但是我得到以下错误(这有点不同):

禁止(403)CSRF验证失败 . 请求中止 . 帮助失败的原因:CSRF令牌丢失或不正确 .

使用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,那么对post请求的响应将成功 . 但这不是首先打败了csrf保护的目的吗?

我不认为Django CSRF check failing with an Ajax POST request有我正在寻找的答案,因为它似乎只适用于旧版本的django .

感谢任何能够帮助我指明正确方向的人!

更新:此配置适用于django 1.4但在django 1.5上我遇到了一些问题 . 在查看Django 1.5发行说明(https://docs.djangoproject.com/en/dev/releases/1.5/#miscellaneous)之后,我发现了这个:"The csrf_token template tag is no longer enclosed in a div. If you need HTML validation against pre-HTML5 Strict DTDs, you should add a div around it in your pages."这对任何人都意味着什么?另外,我在django的文档(https://docs.djangoproject.com/en/dev/ref/contrib/csrf/)中注意到,对于像我这样的情况,页面使用没有表单的ajax,解决方案是"use ensure_csrf_cookie() on the view that sends the page."我注意到了区别 .

如果有人还在读这个,谢谢 .

更新2:如果有人发现我的所有内容的错误,我会很尴尬 . 可能要用假名或其他东西注册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)),
)

回答(1)

2 years ago

尝试添加ensure_csrf_cookie装饰器

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def ajax_view(request):

而且你在template.html中不需要{%csrf_token%}