没有表单的 Django CSRF 令牌

Posted

技术标签:

【中文标题】没有表单的 Django CSRF 令牌【英文标题】:Django CSRF Token without forms 【发布时间】:2011-12-11 05:48:31 【问题描述】:

听起来很奇怪,但是不使用表单(可以从表面读取多个内容)使用 javascript(例如 AJAX)发布内容的场景呢?

我应该在哪里放置 csrf_token 模板标签?我已经添加了 AJAX 修复: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

...但我得到“CSRF 验证失败。请求中止。” 404错误。

【问题讨论】:

【参考方案1】:

您必须在 AJAX 请求中设置自定义 HTTP 标头 X-CSRFToken。见:https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

如果您已经遵循了该建议,那么它应该可以工作。使用 Firebug 之类的东西来监控正在发送的请求并检查标头以确保自定义标头真正被传递。如果不是,请再次检查您的实现,以确保您按照文档描述的那样进行操作。

另请注意:

由于 jQuery 1.5 中引入的错误,上面的示例在该版本上无法正常工作。确保您至少运行 jQuery 1.5.1。

【讨论】:

感谢 Firebug 的提示。那成功了。可以看到 Cookie 中的 Token 和请求中的 Token。发现问题不在我的应用程序的这一部分。回答我的问题:由于这个 Pre-AJAX 功能,模板标签字段不是必需的。对吗? 是的,如果我对文档的理解正确,Django 完全超越了模板标签,更喜欢使用 cookie 来处理 CSRF 令牌。【参考方案2】:

如果您想在没有表单的情况下发布,则配置 CSRF 令牌有两个步骤。基本上从 Cookie 中获取csrftoken,并使用 csrftoken 设置 Header(在您 POST 数据之前)。


1) 从 Cookie 中获取csrftoken

// Function to GET csrftoken from Cookie
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');

2) 获得 csrftoken 后,应使用 csrftoken 设置 Header(在 POST 数据之前)。

function csrfSafeMethod(method) 
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));


// Function to set Request Header with `CSRFTOKEN`
function setRequestHeader()
    $.ajaxSetup(
        beforeSend: function(xhr, settings) 
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) 
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            
        
    );


function postSomeData() 
    .....
    setRequestHeader();

    $.ajax(
        dataType: 'json',
        type: 'POST',
        url: "/url-of-some-api/",
        data: data,
        success: function () 
            alert('success');
        ,
        error: function () 
            alert('error');
        
    );


【讨论】:

【参考方案3】:

这段代码很简单:

$.ajaxSetup( data: csrfmiddlewaretoken: ' csrf_token ' ,);

查看更多:https://***.com/a/7715325/1743582

【讨论】:

【参考方案4】:

一个 CSRF 令牌分配给每个会话(即每次您登录时)。因此,在您希望获取用户输入的一些数据并将其作为 ajax 调用发送到受 csrf_protect 装饰器保护的某个函数之前,请尝试在从用户获取此数据之前找到正在调用的函数。例如。必须呈现一些模板,您的用户正在其上输入数据。该模板正在由某个函数呈现。在此函数中,您可以获得 csrf 令牌,如下所示: csrf = request.COOKIES['csrftoken'] 现在将这个 csrf 值传递到上下文字典中,针对哪个模板正在呈现问题。现在在该模板中写下这一行: 现在在你的 javascript 函数中,在发出 ajax 请求之前,写下: var csrf = $('#csrf').val() 这将选择传递给模板的令牌值并将其存储在变量中csrf.现在,在进行 ajax 调用时,在您的帖子数据中,也传递此值:“csrfmiddlewaretoken”:csrf

即使您没有实现 django 表单,这也可以工作。

事实上,这里的逻辑是:你需要可以从请求中获取的令牌。所以你只需要弄清楚登录后立即调用的函数。一旦你有了这个令牌,要么进行另一个 ajax 调用来获取它,要么将它传递给你的 ajax 可以访问的某个模板。

【讨论】:

以上是关于没有表单的 Django CSRF 令牌的主要内容,如果未能解决你的问题,请参考以下文章

注册表单不起作用(CSRF 令牌丢失或不正确。) django

Django - 在同一个模板(ajax 和表单)中处理多个 CSRF 令牌禁止(CSRF 令牌丢失或不正确。)

Django 表单中的 CSRF 令牌丢失或不正确

在 django 中使用 ajax 表单发布 csrf 令牌的这种方法有啥问题?

你如何在 django rest 框架中实现 CSRF 令牌?

打开新的浏览器选项卡会使 Django 的 CSRF 令牌无效,从而阻止表单提交