未设置 Django CSRF cookie:使用 Ajax 跨站点

Posted

技术标签:

【中文标题】未设置 Django CSRF cookie:使用 Ajax 跨站点【英文标题】:Django CSRF cookie not set: using Ajax Cross site 【发布时间】:2021-06-10 12:22:08 【问题描述】:

我的代码有两部分,首先是一个前端(无框架/库),通过简单的python HTTP serverlocalhost:3000 上运行,以及在localhost:8080 上运行的Django server,发生了什么这里是前端正在向 Django 服务器发出跨站点 POST 请求,但它得到了 Forbidden (CSRF cookie not set.) 错误。我知道这个问题已经被问过很多次了,但我似乎没有找到解决办法。

我没有任何像这样在 Django 中请求 POST 调用的经验,不是使用 DRF 而是使用我们自己的 endpoints

问题代码:

首先前端应向/api/csrf/

发出一个csrf令牌的get请求

views.py:

def get_csrf(request):
    # print(get_token(request))
    return JsonResponse(
        'detail': 'CSRF cookie set',
        'X-CSRFToken': get_token(request)
        )

获取值后,将token分配给cookie和一个隐藏元素 via

main.js:

success: function (response, status, xhr) 
      $('.csrftoken').attr('value', response['X-CSRFToken']);
       setCookie("csrftoken", response['X-CSRFToken']);

上面的代码工作正常,我们得到了值,一开始是这样但没有工作,所以我把它改成这样:

xhr.getResponseHeader("X-CSRFToken") -> response['X-CSRFToken']

现在,每当 frontend 向后端发出 POST 调用,header: 'X-CSRFToken': tokenlocalhost:8080 上运行,它就会得到Forbidden (CSRF cookie not set.) 403

settings.py

INSTALLED_APPS = [
    'corsheaders,
]
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
]
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_HTTPONLY = True
CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
    "http://127.0.0.1:3000"
]

POST 请求

$.ajax(
      type: "POST",
      headers:
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-Requested-With': 'XMLHttpRequest',
        'X-CSRFToken': csrftoken,
      ,
      url: "/api/userdetails/",
      data: JSON.stringify(somedata),
      ...
      ...
)

到目前为止我所尝试的:

我已尝试通过-

获取 csrftoken
# from the hidden element
const csrftoken = document.querySelector('.csrftoken').value;
# from the cookie
const csrftoken = getCCookie('csrftoken');
# from the name
const csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();

所有这些都成功检索了值,我可以在请求标头中看到该值,但 django 仍然说没有 csrftoken 正如文档所说,在设置一个必须从隐藏元素中获取值时使用下面的代码,我再次尝试了它以及没有它:

CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_HTTPONLY = True

Doc 说也试试这个:

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) && !this.crossDomain) 
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            
        

但是这里没有成功尝试,代码有什么问题?以及我应该如何度过难关。

【问题讨论】:

successfully retrieve the value, but unable to put it in the header 请澄清:您的请求中有这个值吗?使用浏览器开发工具检查请求中传递的内容。如果为真,则在您的 settings.py docs.djangoproject.com/en/3.1/ref/settings/#csrf-header-name 中检查此选项值 @IvanStarostin 是的,你是对的,值在请求标头中作为 X-CSRFToken 并且 csrf 标头在 settings.py 中设置为默认值,我应该更正问题的那部分。 【参考方案1】:

您必须在 django html 模板中包含 % csrf_token %。这将创建名为“csrfmiddlewaretoken”的隐藏输入 html 标记。

设置var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();javascript代码必须在呈现html代码之后包含,否则var csrftoken设置为null。

<!DOCTYPE html>
<html>
<body>

<form method="post" action="% url 'django-view-ajax-handle' %" id="ajax-function-id" name="ajax-function-name">
    % csrf_token %
     form 
    <input type="submit" value="Submit">
</form>

// GET CSRF_TOKEN AFTER HTML
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();

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


$(document).ready(function () 
  $("#ajax-function-id").submit(function (event) 

    $.ajax(
      type: "POST",
      url: $('[name="ajax-function-name"]').attr("action"),
      beforeSend: function(xhr, settings) 
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) 
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        
      ,
      success: function (data) 
        // handle_success
      
    );
    return false;
  );
);
</script>
</body>
</html>

【讨论】:

以上是关于未设置 Django CSRF cookie:使用 Ajax 跨站点的主要内容,如果未能解决你的问题,请参考以下文章

未设置 Django CSRF cookie:使用 Ajax 跨站点

Django 1.9 AJAX 表单 CSRF 令牌 403 错误 - “未设置 CSRF cookie”

Django(DRF)和React - 禁止(未设置CSRF cookie)

禁止(未设置 CSRF cookie。):/paypal/ |姜戈

Django Admin登录403 Forbidden(未设置CSRF cookie。)

CSRF cookie 未设置 - 可能被 kubernetes 入口阻止