未设置 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 server
在localhost:3000
上运行,以及在localhost:8080
上运行的Django server
,发生了什么这里是前端正在向 Django 服务器发出跨站点 POST 请求,但它得到了 Forbidden (CSRF cookie not set.) 错误。我知道这个问题已经被问过很多次了,但我似乎没有找到解决办法。
我没有任何像这样在 Django 中请求 POST 调用的经验,不是使用 DRF 而是使用我们自己的 endpoints。
问题代码:
首先前端应向/api/csrf/
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': token
在localhost: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/ |姜戈