如何作为 API 向 Django 检索/提供 CSRF 令牌

2024-04-27

我正在开发一个使用 Django REST Framework 作为后端的项目(假设在api.somecompany.com但有一个 React.js 前端(位于www.somecompany.com) 不由发出 AJAX 请求的 Django 提供服务。

因此,我不能使用 Django 的传统方法让模板包含这样的 CSRF 令牌<form action="." method="post">{% csrf_token %}

我可以向 Django REST Framework 发出请求api-auth\login\url,它将返回此标头:Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/- 但我无法检索此 cookie 以与我的 AJAX 请求一起发回X-CSRFToken(我的理解是单独的子域),并且它似乎不会自动包含在内。

这是我的相关代码:

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

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    }
});

当页面加载时,我调用它以确保我有一个令牌:

$.ajax(loginUrl, { method: "OPTIONS", async: false })
    .done(function(data, textStatus, jqXHR) {
        console.log(jqXHR)
        app.csrftoken@ = $.cookie("csrftoken")
        console.log($.cookie("csrftoken"))
        console.log(app.csrftoken)
    })
    .fail(function(jqXHR, textStatus, errorThrown) {
        console.log(jqXHR)
    });

这并不完全干净,但我还没有向自己证明这个概念。

当前端和后端位于不同的端口/域时,验证/防止 CSRF 的“正确”方法是什么?


事实上,您可以使用允许的请求来源白名单,使其与 CSRF 保护一起工作。

为了使这个工作,你将不得不使用Cross-Origin Resource Sharing(CORS)。为了实现这一目标,我建议创建一个中间件类来设置交叉共享凭据。有一个伟大的要点 https://gist.github.com/strogonoff/1369619概述了如何使用跨源 HTTP 请求标头中的一些构建。如果需要,您可以通过更改请求的原始引用值,以这种方式通过中间件插入 CSRF 令牌。

The django-cors-标题 https://github.com/ottoyiu/django-cors-headers应用程序为您做到这一点。您可以看到他们如何协商 CSRF 令牌他们的中间件文件 https://github.com/ottoyiu/django-cors-headers/blob/1e7bf86310e54cf2520c1b197d4e54bf80004df3/corsheaders/middleware.py,如果你有兴趣的话。

请参阅Django REST CORS 文档 http://www.django-rest-framework.org/topics/ajax-csrf-cors/有关更多信息(他们建议使用 django-cors-headers)。

如果您仍然遇到困难,请尝试:

  1. 设置crossDomain http://%20api.jquery.com/jQuery.ajaxAJAX 请求的参数True。有时,如果未指定,jQuery 将不会处理请求。
  2. 如果您仍然没有在请求中收到令牌标头,请尝试附加ensure_csrf_cookie() https://docs.djangoproject.com/en/dev/ref/csrf/#django.views.decorators.csrf.ensure_csrf_cookie围绕你的视图方法的装饰器。有时候,当没有的时候{% csrf_token %}页面上的模板标记(如果您不渲染表单),Django 根本不会在请求中包含令牌。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何作为 API 向 Django 检索/提供 CSRF 令牌 的相关文章

随机推荐