Django - 在同一个模板(ajax 和表单)中处理多个 CSRF 令牌禁止(CSRF 令牌丢失或不正确。)

Posted

技术标签:

【中文标题】Django - 在同一个模板(ajax 和表单)中处理多个 CSRF 令牌禁止(CSRF 令牌丢失或不正确。)【英文标题】:Django - dealing with multiple CSRF tokens in the same template (ajax and form) Forbidden (CSRF token missing or incorrect.) 【发布时间】:2019-02-07 16:19:00 【问题描述】:

我有这个模板,其中有一个用于提交电子邮件地址的表单,我正在尝试制作一个复选框,以便用户可以选择是否接收电子邮件通知。

% extends "base_generic.html" %

% block content %
<h1> user.username </h1>

<p> Email comfirmed?  user.profile.email_confirmed </p>

% if user.profile.email_confirmed %
  <p>Email confimed as  user.email </p>
% else %
<form method="post">
    % csrf_token %
    % for field in form %
      <p>
         field.label_tag <br>
         field 
        % if field.help_text %
          <small style="color: grey"> field.help_text </small>
        % endif %
        % for error in field.errors %
          <p style="color: red"> error </p>
        % endfor %
      </p>
    % endfor %
    <button type="submit">Authentificate</button>
  </form>
% endif %
% if posts %
<p>Your posts: </p>
<ul>
      <li>  posts.author   posts.pub_date 
          % if post.last_edited != null %
            Last edited:  post.last_edited 
          % endif %
              <br>  
      <a href="% url 'fortykwords:detail' posts.id %"> posts.title </a></li>
      % for tag in posts.tags.all %
          <a href="% url 'fortykwords:tag' tag.name %"> tag.name </a>
      % endfor %

% endif %
</ul>
% else %
  <p>No posts are available.</p>
% endif %

<input type="checkbox" name="checkbox" id="request.user.id">Send me an email notifications when I receive a message.<br>


    <script type="text/javascript">
    window.CSRF_TOKEN = " csrf_token ";
      $(document).ready(function()
          $("input:checkbox").change(function()  
              if($(this).is(":checked"))  
                  $.ajax(
                      url: "/permissions/",
                      type: 'POST',
                      data:  strID:$(this).attr("id"), strState:"1" ,
                      csrfmiddlewaretoken: jQuery("[name=csrfmiddlewaretoken]").val(),
                  
                );
               else 
                  $.ajax(
                      url: "/permissions/",
                      type: 'POST',
                      data:  strID:$(this).attr("id"), strState:"0" ,
                      csrfmiddlewaretoken: jQuery("[name=csrfmiddlewaretoken]").val(),
                  );
              
          ); 
      );
  </script>
% endblock %

问题是当我点击复选框时,它给了我以下错误:

[02/Sep/2018 09:22:54] "POST /permissions/ HTTP/1.1" 403 2513
Forbidden (CSRF token missing or incorrect.): /permissions/

我知道这与 CSRF 令牌有关,但我尝试了很多变体,但我不知道它可能是什么。我怀疑这是因为我将一个令牌用于表单,另一个用于 AJAX 请求。我应该更改什么才能成功提交 CSRF 令牌?

【问题讨论】:

可能是因为你的 标签不在表单中? 糟糕!但是我改成&lt;form&gt; &lt;input type="checkbox" name="checkbox" id="request.user.id"&gt;Send me an email notifications when I receive a message.&lt;br&gt; &lt;/form&gt;还是不行。 也许这与您的问题有关? ***.com/questions/5100539/… 我不确定您的 Ajax 为何试图再次从输入中获取令牌。你已经有了它,在window.CSRF_TOKEN;你应该使用它.. 您需要在您的 ajax 请求中添加一个标头变量,名为:'X-CSRFToken',这样您的标头将包含 'X-CSRFToken': PUT_YOUR_CSRF_TOKEN_HERE 【参考方案1】:

在AJAX docs,我没有看到任何设置选项csrfmiddlewaretoken

您需要在数据或设置标头X-CSRFToken 中传递令牌。

解决方案

$.ajax(
  url: "/permissions/",
  type: 'POST',
  data: 
    strID: $(this).attr("id"),
    strState: "0",
    csrfmiddlewaretoken: jQuery("[name=csrfmiddlewaretoken]").val()
  ,
  // or you can set the header
  // headers: 
  //   "X-CSRFToken": jQuery("[name=csrfmiddlewaretoken]").val()
  // 
)

【讨论】:

以上是关于Django - 在同一个模板(ajax 和表单)中处理多个 CSRF 令牌禁止(CSRF 令牌丢失或不正确。)的主要内容,如果未能解决你的问题,请参考以下文章

在 AJAX 请求后填充 Django 表单

使用 Django 实现 ajax 表单

django 如何写表单提交

Django 中的 Ajax 正在创建重复元素

Django + ajax + 模态表单 bootstrap5.如何让它发挥作用?

为啥django不处理PUT方法带过来的表单