在Django+Vue设置中不断获取403“CSRF令牌丢失或不正确”

2024-06-16 13:09:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我搜索了其他类似的问题,但没有一个解决方案奏效,也没有让我对可能发生的事情有任何洞察

我的设置是一个Vue前端(有自己的路由),外加一个Django后端和API。我尝试的任何GET路径都能按预期工作,但POST路径需要CSRF保护。我有一个自定义的渲染函数,我在路由上调用它来创建索引(然后将由Vue处理),其中我提供了CSRF令牌,如下所示:

def custom_render(request):
    # ...

    # from django.middleware.csrf
    get_token(request)

    # from django.shortcuts
    return render(request, template)

这将设置一个带有CSRF令牌的cookiecsrftoken,它似乎工作正常,因为我可以在devtools中看到它,如果我删除它,刷新时它会再次出现。以下是我的相关Django settings.py

# This one is True in production, but for now I'm testing locally
CSRF_COOKIE_SECURE = False

CSRF_HEADER_NAME = "X-CSRFToken"

# I tried playing with both these options' values to no avail
CSRF_USE_SESSIONS = False
CSRF_COOKIE_HTTPONLY = False


MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "django.middleware.common.BrokenLinkEmailsMiddleware",
]

在Vue端(Typescript),我使用以下命令发送请求:

function getCsrfToken() {
  return document.cookie.match("(^|;)\\s*" + "csrftoken" + "\\s*=\\s*([^;]+)")?.pop()
}

fetch(
  "api/my-route/",
  {
    method: "POST",
    headers: {
      "X-CSRFToken": getCsrfToken(),
      "Content-Type": "application/json",
      "Accept": "application/json",
    },
    mode: "same-origin",
    body: JSON.stringify(dataToSend),
  },
)

正如我在devtools中看到的那样,这也是预期的效果,请求确实包含与csrftokencookie内容相同的X-CSRFToken头。然而,响应仍然是403,声称令牌丢失或不正确。我不确定Django是否认为它丢失了或者它是否认为它不正确,所以我不确定如何继续。连接调试器是不切实际的,因为我不知道应该停止执行的内部方法是什么,所以我被卡住了

编辑:我最近尝试过的其他方法:

  • 在后端,将自定义渲染函数中的get_token()替换为主视图中的@ensure_csrf_cookie装饰器。奇怪的是,这并没有导致csrf cookie按预期设置
  • 再次在后端,将@csrf_protect装饰器添加到主视图。这确实导致了csrf cookie被设置,尽管我不太明白为什么。无论如何,这并没有解决问题
  • 在前端,将csrfmiddlewaretoken字段添加到POST请求主体中,标记作为值
  • 再次在前端,使用Django文档中显示的完全相同的函数(而不是我的自定义函数)获取令牌

不幸的是,所有这些都没有改变结果:当我有可用的cookie时,它的值似乎并不满足Django


Tags: django函数路径false路由cookierequestcontrib
1条回答
网友
1楼 · 发布于 2024-06-16 13:09:41

我发现了一个问题:我设置中的CSRF_HEADER_NAME = "X-CSRFToken"没有考虑到Django隐式规范化了所有头名称,使得请求中的标记看起来像HTTP_X_CSRFTOKEN,但不需要对自定义名称做同样的操作,因此,在Django比较这两种情况时,这两种情况是不匹配的

相关问题 更多 >