Django 1.9 AJAX 表单 CSRF 令牌 403 错误 - "CSRF cookie not set"
Django 1.9 AJAX form CSRF token 403 error - "CSRF cookie not set"
我在 SO 上看到了很多关于这个的信息,但没有什么能解决我的问题。
问题:
启用 CSRF 中间件后,Django 在 AJAX 表单请求上以 403 响应,说明:
"CSRF cookie not set."
在 documentation 之后,实现了一个 JS 功能,设置自定义 "X-CSRFToken" header.
它按预期工作,从浏览器获取 "csrftoken" cookie 并将其与 AJAX 请求一起发布:
x-csrftoken: 1a0u7GCQG0wepZHQNThIXeYpMy2lZOf2
但是响应还是403
尝试过的解决方案:
我已经尝试了在 SO 或网络上可以找到的所有内容,特别是:
正在检查中间件是否已启用:
MIDDLEWARE_CLASSES = [
...
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
]
启用 cookie 的不同浏览器;
用@ensure_csrf_cookie
装饰我的视图;
在我的模板中设置{% csrf_token %}
;
使用 render
获取正确请求上下文的快捷方式;
在我的 settings.py
中设置自定义 CSRF_COOKIE_NAME
和 CSRF_HEADER_NAME
;
明确设置CSRF_COOKIE_SECURE = False
和CSRF_COOKIE_HTTPONLY = False
;
显式设置CSRF_TRUSTED_ORIGINS
设置;
在开发和生产服务器上测试;
甚至 request.META["CSRF_COOKIE_USED"] = True
在我看来,正如有人建议的那样。
仍然一无所获。
Headers:
如果我在我看来使用 @csrf_exempt
和 print(request.META)
,很明显自定义 header "X-CSRFToken" 存在于根据 Django 文档请求和格式化,带有 "HTTP_" 前缀,用下划线替换连字符,全部大写:"HTTP_X_CSRFTOKEN".
更重要的是,它的值与 Django 设置的 cookie 匹配。
Cookies:
奇怪的是,如果我尝试 print(request.COOKIES)
在我的视图中,在页面和表单加载时我可以看到 "csrftoken" cookie,但是字典在 AJAX 请求 上 为空。会不会是问题所在?
急于找出问题所在。感谢您阅读本文。
ok,那么问题就很简单了:
Fetch API 默认情况下不发送凭据。根据MDN:
The credentials read-only property of the Request interface indicates
whether the user agent should send cookies from the other domain in
the case of cross-origin requests. This is similar to XHR’s
withCredentials flag, but with three available values.
默认为 omit
,它从不发送 cookie。您只需要将 same-origin
添加到 fetch()
函数参数中:
fetch(formUrl, {
...
credentials: 'same-origin',
...
})
你会很高兴的:)
我在 SO 上看到了很多关于这个的信息,但没有什么能解决我的问题。
问题:
启用 CSRF 中间件后,Django 在 AJAX 表单请求上以 403 响应,说明:
"CSRF cookie not set."
在 documentation 之后,实现了一个 JS 功能,设置自定义 "X-CSRFToken" header.
它按预期工作,从浏览器获取 "csrftoken" cookie 并将其与 AJAX 请求一起发布:
x-csrftoken: 1a0u7GCQG0wepZHQNThIXeYpMy2lZOf2
但是响应还是403
尝试过的解决方案:
我已经尝试了在 SO 或网络上可以找到的所有内容,特别是:
正在检查中间件是否已启用:
MIDDLEWARE_CLASSES = [ ... 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ... ]
启用 cookie 的不同浏览器;
用
@ensure_csrf_cookie
装饰我的视图;在我的模板中设置
{% csrf_token %}
;使用
render
获取正确请求上下文的快捷方式;在我的
settings.py
中设置自定义CSRF_COOKIE_NAME
和CSRF_HEADER_NAME
;明确设置
CSRF_COOKIE_SECURE = False
和CSRF_COOKIE_HTTPONLY = False
;显式设置
CSRF_TRUSTED_ORIGINS
设置;在开发和生产服务器上测试;
甚至
request.META["CSRF_COOKIE_USED"] = True
在我看来,正如有人建议的那样。
仍然一无所获。
Headers:
如果我在我看来使用 @csrf_exempt
和 print(request.META)
,很明显自定义 header "X-CSRFToken" 存在于根据 Django 文档请求和格式化,带有 "HTTP_" 前缀,用下划线替换连字符,全部大写:"HTTP_X_CSRFTOKEN".
更重要的是,它的值与 Django 设置的 cookie 匹配。
Cookies:
奇怪的是,如果我尝试 print(request.COOKIES)
在我的视图中,在页面和表单加载时我可以看到 "csrftoken" cookie,但是字典在 AJAX 请求 上 为空。会不会是问题所在?
急于找出问题所在。感谢您阅读本文。
ok,那么问题就很简单了:
Fetch API 默认情况下不发送凭据。根据MDN:
The credentials read-only property of the Request interface indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests. This is similar to XHR’s withCredentials flag, but with three available values.
默认为 omit
,它从不发送 cookie。您只需要将 same-origin
添加到 fetch()
函数参数中:
fetch(formUrl, {
...
credentials: 'same-origin',
...
})
你会很高兴的:)