Django:使用AJAX登录,我应该如何更新表单的CSRF令牌?



上下文:

我正在做的一个公司项目是使用AJAX让用户登录网页上的某些操作。此网页可以在不登录的情况下查看,但某些操作需要身份验证(如更新硬件的设置(。我想保留用户当前拥有的表单,这样他们就不必重新输入更改(我目前正在通过隐藏表单并覆盖"登录"表单来进行更改(,因此刷新页面不是一种选择,或者至少是最后的手段。

问题:

登录完成后,第一个表单的CSRF令牌现在无效,需要更新。这不是一个";"我如何向AJAX请求添加CSRF令牌";,而是一个";我如何更新它";。

Django在登录后抛出以下错误:Forbidden (CSRF token from POST incorrect.)

以下是我已经尝试过的:

登录后发送表单的新CSRF令牌(服务器端(:

form = AuthenticationForm(data=request.POST or None)
if form.is_valid():
# Login the user
user = authenticate(
username=form.cleaned_data.get("username"),
password=form.cleaned_data.get("password"),
)
if user is not None:
login(request, user)
# Neither of these have worked
# return JsonResponse(dict(success=True, csrfToken=request.POST.get("csrfmiddlewaretoken")))
# return JsonResponse(dict(success=True, csrfToken=str(csrf(request)["csrf_token"])))

在客户端

// From Django's AJAX documentation
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 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;
}
...
// Submit the login information and then update the page's CRSF token
// This is first and is run when the user is anonymous
$.ajax({
url: $("#login-form").attr("action"),
type: "POST",
data: data,
headers: {
'X-CSRFToken': getCookie("csrftoken"),
},
processData: false,
contentType: false,
success: function(data) {
// Update the new CSRF token
csrfToken = data["csrfToken"];
...
// Submit the settings form with (hopefully) an updated CSRF token
// This is second and is run when the user is authenticated
// Spoiler: it doesn't work
$.ajax({
url: $("#settings-form").attr("action"),
type: "POST",
data: data,
headers: {
'X-CSRFToken': getCookie("csrftoken"),
},
processData: false,
contentType: false,

我100%承认我对AJAX或CSRF代币没有太多经验,所以如果我做错了什么,那是因为我缺乏经验。我在任何地方都没有看到任何其他关于这样一个问题的帖子(99%是"我如何添加CSRF令牌"的问题(,但我愿意看看你认为可能相关的任何帖子。

提前感谢您抽出时间。

Jules

感谢@thebjorn在我上面帖子的评论中,我能够确定我也未能更新表单上的CSRF令牌。

不幸的是,无论出于什么原因,我确信有人比我更聪明,使用我在登录表单的POST请求中发送回客户端的CSRF令牌仍然会引发这个问题。作为一个解决方案,我使用fetchAPI,并从Django中获取一个新的API。这似乎奏效了。

对于那些找到这篇文章的人来说,这是上面更新的登录AJAX代码:

// Store the csrf token here and update this variable
// upon user login
var csrfToken = getCookie("csrftoken");
// Submit the login information and then update the page's CRSF token
// This is first and is run when the user is anonymous
$.ajax({
url: $("#login-form").attr("action"),
type: "POST",
data: data,
headers: {
'X-CSRFToken': csrfToken,
},
processData: false,
contentType: false,
success: function(data) {
// Update the new CSRF token
fetch(window.location.href, {
headers: {
"X-CSRFTOKEN-ONLY": "True"  // Custom header
}
})
.then(response=>response.json())
.then(data_ => {
console.log(data_);
csrfToken = data_["csrftoken"];
$("#settings-form [name=csrfmiddlewaretoken]").val(data_["csrftoken"]);
...

再次感谢@thebjorn和@YevgeniyKosmak的帮助。

我有一个简单的方法:

在ajax标头中:headers:{'X-CSRFToken':getCookie('CSRFToken'(},

别忘了放getcookie函数:

function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 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;
}
const csrftoken = getCookie('csrftoken');

最新更新