"Forbidden (CSRF token missing or incorrect.):" 使用 Django 和 JS

"Forbidden (CSRF token missing or incorrect.):" using Django and JS

我正在我的 JS 代码中使用 Axios 执行 POST 请求,以将一些信息发送到我本地托管的 Django 服务器。我的 html 代码表单中有 {% csrf_token %} 但不知道如何使用 Axios 发送 csrf 令牌。

我在终端中收到此错误: “禁止(CSRF 令牌丢失或不正确。):/api/scoring/submit_score_details”。

如何在我的 axios post 中正确插入 csrf 令牌?现在,我认为 JS 无法像我那样读取 {{ csrf_token }} 。我一直在搜索 Stack,但似乎大多数人都在使用 jQuery 或其他类型的 JS。

为了节省 space 我没有 post 有效载荷中的变量是什么,但它们都是字符串。

如果我在 views.py 文件中将 @csrf_exempt 放在我的函数上方,我可以让错误消失。

{
let payload = {
    "csrfmiddlewaretoken": "{{ csrf_token }}",
    "math_problem": problem,
    "user_answer": userInput,
    "true_answer": correctAnswer,
    "question_status": questionStatus,
}
console.log(payload);
axios.post('../api/scoring/submit_score_details', payload)
}
<div class="col text-center">
    <button id="start" type="button" class="btn btn-primary btn-lg">
        New Problem
    </button>
    <p id="math_problem"></p>
    <form id="inputForm" method="POST">
        {% csrf_token %}
        <input id="user_input" autocomplete="off" class="form-control form-control-lg" type="text" placeholder="Type your answer here">
        <input id="correct_answer" type="hidden">
    </form>
    <br>
    <button id="result_check" type="button" class="btn btn-primary btn-lg">Check</button>
    <script src={% static 'js/game_logic.js' %}></script>
</div>

{
let payload = {
    "csrfmiddlewaretoken": "{{ csrf_token }}",
    "math_problem": problem,
    "user_answer": userInput,
    "true_answer": correctAnswer,
    "question_status": questionStatus,
}
console.log(payload);
axios.post('../api/scoring/submit_score_details', payload)
}
<form id="inputForm" method="POST">
    {% csrf_token %}
    <input id="user_input" autocomplete="off" class="form-control form-control-lg" type="text" placeholder="Type your answer here">
    <input id="correct_answer" type="hidden">
</form>

您的 Axios 代码是否可能在页面中呈现 csrf_token 之前创建(通过 django 模板)?

尽早在您的 js 代码中尝试这样的事情:

var my_token = '{{ csrf_token }}';

然后当你调用 Axios 时,发送这个值,而不是渲染 {{ csrf_token }} 内联,所以像这样:

{
    let payload = {
        "csrfmiddlewaretoken": my_token,
        "math_problem": problem,
        "user_answer": userInput,
        "true_answer": correctAnswer,
        "question_status": questionStatus,
    }
    console.log(payload);
    axios.post('../api/scoring/submit_score_details', payload)
}

我也很好奇你是否看到你的 csrf 令牌在你显示的代码中被打印到控制台(从打印出有效载荷),因为这将表明它是否被发送。

如果正在发送 csrf_token,应用程序可能会出现其他问题,但是一旦您在 my_token 中获得了令牌,您就可以将其打印出来并确保它已正确设置并从那里开始工作。

好吧,回顾一下讨论,我想我可能知道这里发生了什么......

也许你已经在你的 JS 中添加了“{{ csrf_token }}”(存储在静态代码中的某个地方)——这是行不通的,因为正如你所指出的,JS 对Django 模板。

这样做的方法是将您的 JS 代码更改为使用 JS 变量(例如 my_token)。

{
    let payload = {
        "csrfmiddlewaretoken": my_token, // populated later within form
        "math_problem": problem,
        "user_answer": userInput,
        "true_answer": correctAnswer,
        "question_status": questionStatus,
    }
    console.log(payload);
    axios.post('../api/scoring/submit_score_details', payload)
}

此 my_token 值将在稍后(在您的表单中)进行 Axios 调用之前提供。为此,请在您的表单中添加:

<script>
    // This will be rendered by Django to get the actual string into my_token
    var my_token = "{{ csrf_token }}"; 
</script>

然后,当您进行 Axios 调用时(通过单击按钮或定时器或其他方式),应正确设置和使用此全局变量。

所以我最后做了一些谷歌搜索并问了一个朋友。我们想出了一个解决方案。

我们必须添加两行代码才能使事情正常进行:

axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';

我们还去掉了 'payload' 变量,将所有内容都放在 Axios 代码中。

{
        axios.defaults.xsrfCookieName = 'csrftoken';
        axios.defaults.xsrfHeaderName = 'X-CSRFToken';
        axios.post('../api/scoring/submit_score_details', {
            "math_problem": problem,
            "user_answer": userInput,
            "true_answer": correctAnswer,
            "question_status": questionStatus,
        });
        console.log(`Problem:${problem},
                     User Input: ${userInput},
                     Correct Answer: ${correctAnswer},
                     Question Status: ${questionStatus}`
                     );
    };
<div class="col text-center">
    <button id="new_problem_button" type="button" class="btn btn-primary btn-lg">
        New Problem
    </button>
    <p id="math_problem"></p>
    <form id="inputForm" method="POST">
        {% csrf_token %}
        <input id="user_input" autocomplete="off" class="form-control form-control-lg" type="text" placeholder="Type your answer here">
        <input id="correct_answer" type="hidden">
    </form>
    <br>
    <button id="result_check" type="button" class="btn btn-primary btn-lg">Check</button>
    <script src={% static 'js/game_logic.js' %}></script>
</div>

Here's link 对我们有帮助。