[英]Django: using AJAX for login, how do (should) I update a form's CSRF Token?
语境:
我正在从事的一个公司项目正在使用 AJAX 登录用户以在网页上执行某些操作。 无需登录即可查看此网页,但某些操作需要身份验证(如更新硬件设置)。 我想保留用户当前拥有的表单,这样他们就不必重新输入他们的更改(我目前正在通过隐藏表单并覆盖“登录”表单来做)所以刷新页面不是一个选项,或者至少,最后的手段。
问题:
登录完成后,第一个表单的 CSRF token 无效,需要更新。 这不是“如何将 CSRF 令牌添加到 AJAX 请求”的问题,而是“如何更新它”的问题。
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 令牌”问题),但我愿意查看您认为可能相关的任何帖子。
预先感谢您的宝贵时间。
朱尔斯
感谢@thebjorn 在我上面帖子的评论中,我能够确定我也未能更新表单上的 CSRF 令牌。
不幸的是,无论出于何种原因,我确信有人比我知道的更聪明,使用我在登录表单的 POST 请求中发送回客户端的 CSRF 令牌继续引发此问题。 作为一种解决方法,我正在使用fetch
API 并从 Django 中提取一个新的。 这似乎有效。
为那些找到这篇文章的人将来参考,这里是上面更新的登录 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: headers: {'X-CSRFToken': getCookie('csrftoken')},
不要忘记把 getcookie function:
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');
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.