【问题标题】:no csrf token after ajax page loadajax页面加载后没有csrf令牌
【发布时间】:2014-02-06 01:17:01
【问题描述】:

现在我已经设置好了,当成功登录时,登录 div 会消失并出现一个注销按钮。我希望能够点击注销并转到我的注销功能,该功能只是重定向到原始登录页面,但由于某种原因,在(仅成功的)ajax 表单提交后突然出现 403 错误:失败原因:CSRF令牌丢失或不正确。

想知道问题是否在于我没有正确传递 CSRF 令牌。我已经尝试了页面上的所有内容https://docs.djangoproject.com/en/1.6/ref/contrib/csrf/#ajax

这是我的代码:

urls.py

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'reportgenerator.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),

    url(r'^admin/', include(admin.site.urls)),
    url(r'^login/', 'reportgenerator.views.login'),
    url(r'^logout/', 'reportgenerator.views.logout'),
)

views.py

class LoginForm(forms.Form):
username = forms.CharField(max_length=200)
password = forms.CharField(max_length=200)

def login(request):
    c = {}
    c.update(csrf(request))

    if request.POST:
        form = LoginForm(request.POST)
        if form.is_valid():
            user = auth.authenticate(username = form.cleaned_data['username'],
                password = form.cleaned_data['password'])
            is_success = False
            if user is not None:
                auth.login(request, user)
                is_success = True

            if request.is_ajax():
                if (is_success):
                    return render_to_response('login.html', c, context_instance = RequestContext(request))

            return render('was_failure')
    else:
        form = LoginForm()

    c['form'] = form
        return render(request, 'login.html', c)

def logout(request):
        auth.logout(request)
        return HttpResponseRedirect('/login/')

还有我的javascript:

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

jQuery(function() {
  var form1 = jQuery("#contactform");

  form1.submit(function(e) {
    $.ajax({
        type: "POST",
        url: form1.attr('action'),
        data: form1.serializeArray(),
        success: function() {
            popup.setAttribute("style","display: none;");
            blurback.setAttribute("style", "-webkit-filter: blur(0px)");
            $("#welcome").fadeIn("slow");
            $("#logoutfade").fadeIn("slow");
        },
        error: function() {
            document.getElementById("password").value = "";
        }
    });
      e.preventDefault(); 
  });
});

【问题讨论】:

    标签: jquery ajax django django-forms


    【解决方案1】:

    Django 提供了关于如何执行需要 CSRF 的 ajax 请求的非常详细的信息: https://docs.djangoproject.com/en/1.6/ref/contrib/csrf/

    在没有 jquery cookie 插件的情况下使用 jQuery:

    // using jQuery
    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');
    

    将 Jquery 与 jquery cookie 插件一起使用:

        var csrftoken = $.cookie('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 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);
            }
        }
    });
    

    编辑(对您的回答) 更通用的方法: 首先确保您启用了中间件:

        'django.middleware.csrf.CsrfViewMiddleware',
    

    然后在你的JS文件中:

    $(document).on('click', '.some-class', function(){
        var $csrftoken = $.cookie('csrftoken');
        $.ajax({
            type: 'POST',
            url: /your/url/,
            crossDomain: false,
            beforeSend: function(xhr) {
                xhr.setRequestHeader("X-CSRFToken", $csrftoken);
            },
            success: function(ctx) {
                console.log(Success!)
            }
        });
    });
    

    【讨论】:

    • 嘿,是的,我整天都在盯着这个文档并试图实现它,但这并没有真正的帮助。如何在我的代码中准确地传递这个?
    • 不,我根本无法让它工作。我在提交我的第一个 ajax 表单时没有任何问题,一切顺利,然后我的成功功能正常运行。然后,当我单击注销按钮并尝试重定向到 /logout/ 时,我就遇到了问题。事实上,除非我成功返回,否则一切正常,然后我遇到了 csrf 问题。
    【解决方案2】:

    为了跟进这件事——几天后我想通了。我遇到此问题的原因是因为在 ajax 登录之前存在注销按钮。当用户通过身份验证时,crsf 令牌被重新生成,并且页面的注销按钮附加了旧令牌,因为它是之前生成的。我将其切换为在 ajax 调用后生成登录按钮,一切正常。

    【讨论】:

      猜你喜欢
      • 2012-05-28
      • 1970-01-01
      • 2015-07-30
      • 2021-10-19
      • 1970-01-01
      • 1970-01-01
      • 2017-01-22
      • 2016-09-11
      • 2015-12-23
      相关资源
      最近更新 更多