繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM