CSRF错误Django ajax .post没有表格

Posted

技术标签:

【中文标题】CSRF错误Django ajax .post没有表格【英文标题】:CSRF Error Django ajax .post with no form 【发布时间】:2014-04-26 18:14:13 【问题描述】:

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

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

禁止 (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('')

模板.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 sn-p:

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) 后,我发现:“csrf_token 模板标签不再包含在 div 中。如果您需要针对 pre-HTML5 Strict DTD 进行 HTML 验证,您应该在您的页。”这对任何人都意味着什么?另外,我在 django 的文档 (https://docs.djangoproject.com/en/dev/ref/contrib/csrf/) 中注意到,对于像我这样的页面使用 ajax 而没有表单的情况,解决方案是“在发送页面的视图上使用 ensure_csrf_cookie()”。我试过了,但我没有注意到有什么不同。

如果有人还在读这篇文章,谢谢。

更新 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)),
)

【问题讨论】:

看起来您的 POST url 与您收到 csrftoken 的位置不同。这可能会导致令牌无效。 我的帖子网址是“127.0.0.1:8000/ajax”,我正在从“127.0.0.1:8000”接收 csrf 令牌。我同意网址不同,但为什么会导致令牌无效?您是否有任何指向更多资源的链接来解释为什么需要这样做? 【参考方案1】:

尝试添加 ensure_csrf_cookie 装饰器

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def ajax_view(request):

而且你不需要 template.html 中的 % csrf_token %

【讨论】:

你说得对,我不需要 csrf 模板标签(我认为现在我认为这只是表单需要),但我仍然没有任何运气。我想我将不得不等待 djangocon 2014 大声笑 你能把你的网址文件贴出来吗? 我的网址已经上线了。希望对您有所帮助。 奇怪,但你的代码工作正常,我只改变了一些东西,` $(".ajax_trigger").click(function() $.post("/ ajax/",data:"test",function(),'json'); ` 也缺少 ** ):** 在 jquery.js 文件的末尾 最后的大括号只是一个错字。在实际代码中,我并没有将它们关闭,而是很好地抓住了;)至于帖子的网址,不幸的是,我对您的更改没有任何运气。有趣的是,当我从“http:/full_url”更改为“/ajax/”时,即使在视图上使用了@CSRF_exempt,我也会收到 CSRF 错误。我想知道问题是否出在我的浏览器或 Django 外部的其他东西上。

以上是关于CSRF错误Django ajax .post没有表格的主要内容,如果未能解决你的问题,请参考以下文章

Django CSRF 令牌错误或缺少 Ajax POST 请求

Django 如何让ajax的POST方法带上CSRF令牌

在 Django 中的 ajax POST 期间被禁止(CSRF 令牌丢失或不正确。)

如何在Django使用ajax的POST

错误:“CSRF 验证失败。请求中止。”在 Django 中使用 jquery ajax 时

Django:AJAX + CSRF POST 给出 403