【问题标题】:How do I include Django 1.2's CSRF token in a Javascript-generated HTML form?如何在 Javascript 生成的 HTML 表单中包含 Django 1.2 的 CSRF 令牌?
【发布时间】:2011-04-15 10:36:52
【问题描述】:

我最近升级到 Django 1.2.3,我的上传表单现在已经损坏。每当我尝试上传时,我都会收到“CSRF 验证失败。请求中止”。错误信息。

阅读 Django's documentation 关于这个主题后,它指出我需要在我的模板中的 HTML <form> 中添加 {% csrf_token %} 模板标签。不幸的是,我的<form> 是通过 JavaScript 生成的(特别是面板上 ExtJs 的“html”属性)。

长话短说,当我的 <form> 未包含在 Django 模板中时,如何将所需的 CSRF 令牌标签添加到我的 <form>

【问题讨论】:

    标签: javascript django extjs csrf django-csrf


    【解决方案1】:

    这将使用 csrf 令牌或在需要时自动生成一个新令牌。它将处理页面上的所有表单提交。如果您有非现场表单,则需要确保它们不会运行此代码。

    <script>
    $(document).on('submit', 'form[method=post]', function(){
      if(!document.cookie.match('csrftoken=([a-zA-Z0-9]{32})')) {
        for(var c = ''; c.length < 32;) c += 'abcdefghijklmnopqrstuvwxyz'.charAt(Math.random() * 26)
        document.cookie = 'csrftoken=' + c + '; path=/'
      }
      if(!this.csrfmiddlewaretoken) $(this).append('<input type="hidden" name="csrfmiddlewaretoken">')
      $(this.csrfmiddlewaretoken).val(document.cookie.match('csrftoken=([a-zA-Z0-9]{32})')[1])
    })
    </script>
    

    需要 jQuery 1.7+

    【讨论】:

      【解决方案2】:

      最简单的方法是使用 django 在您的页面上创建一个不做任何事情的隐藏表单。然后使用 JavaScript 获取表单,特别是表单中的令牌输入。最后,将该令牌输入插入或复制到您动态生成的表单中。

      下面是两个示例,说明如何为 JavaScript 发布令牌。

      <input id="csrf_token" value="{{ csrf_token }}"/>
      
      <script type="text/javascript">
      var CSRF_TOKEN = document.getElementById('csrf_token').value;
      </script>
      

      <script type="text/javascript">
      var CSRF_TOKEN = "{{ csrf_token }}";
      </script>
      

      【讨论】:

      • @Huuuze:将{csrf_token} 放在模板中某处,并在表单构建期间使用JavaScript 对其进行解析。
      【解决方案3】:

      这可能并不理想,但对我来说这是最快的解决方案。在“正文”底部的主模板中,我向我的库中添加了一个 javascript 函数。

      <script type="text/javascript">
          MyToolkit.Utils.getCSRFToken = function () {
               return "{% csrf_token %}";
          };
      </script>
      

      【讨论】:

      • 该标签返回一个隐藏的 div。我想你的意思是 {{ csrf_token }}
      【解决方案4】:

      更好的解决方案是从视图/模板生成js文件的代码。

      然后,在视图中,您可以像这样在上下文中设置 csrf 令牌...

      from django.core.context_processors import csrf
      context = RequestContext(request)
      context.update(csrf(request))
      

      然后,在模板中,您可以使用 {{ csrf_token }} 获取 csrf 令牌的原始值,然后使用它在表单中构建一个名为 csrfmiddlewaretoken 的隐藏字段。

      【讨论】:

        【解决方案5】:

        另一种选择是使用 Ext 调整 the Django docs 中显示的基于 cookie/header 的解决方案 - 如果您有很多模板并且不想更改每一个模板,则更可取。

        只需将以下 sn-p 放入您的 overrides.js(或您放置全局修改的任何位置):

        Ext.Ajax.on('beforerequest', function (conn, options) {
           if (!(/^http:.*/.test(options.url) || /^https:.*/.test(options.url))) {
             if (typeof(options.headers) == "undefined") {
               options.headers = {'X-CSRFToken': Ext.util.Cookies.get('csrftoken')};
             } else {
               options.headers.extend({'X-CSRFToken': Ext.util.Cookies.get('csrftoken')});
             }                        
           }
        }, this);
        

        (编辑:Ext已经有cookie读取功能,无需复制)

        【讨论】:

        • 我需要在动态生成的表单中做/添加什么吗?
        • @john2x:不,您只需将代码放入您的 overrides.js 中。如果你不熟悉 overrides.js 的概念,下面的博客是一个好的开始:edspencer.net/2009/07/extoverride-monkey-patching-ext-js.html
        • +1。太棒了,当我找到这个答案时,我也在思考同样的问题!
        • 另外值得注意的是,如果您的模板不包含{% csrf_token %}csrftoken cookie 可能不存在。要强制始终设置 cookie,请使用导入为 from django.views.decorators.csrf import ensure_csrf_cookie@ensure_csrf_cookie 装饰您的视图。见docs.djangoproject.com/en/1.8/ref/csrf/#ajax
        【解决方案6】:

        POSTing 的视图是否也回复GET?因为 JS 代码可以向相关视图发出 GET 请求并解析输出以提取 CSRF 令牌。我的 JS-fu 很弱,我不确定从客户端进行解析的效果如何。

        有关广泛的相关示例,请参阅this question。在这种情况下,用户尝试使用 Python 脚本 POST 并由于同样的原因而失败。解决方案是相同的,只是他必须使用 Python 脚本而不是 JavaScript。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-18
          • 2016-08-03
          • 2012-02-01
          • 2014-08-31
          • 2021-10-19
          • 2011-12-11
          相关资源
          最近更新 更多