【问题标题】:How to include the CSRF token in the headers in Dropzone upload request?如何在 Dropzone 上传请求的标头中包含 CSRF 令牌?
【发布时间】:2015-07-20 20:33:45
【问题描述】:

我正在开发一个单页应用程序,并且我正在使用 Laravel 5 作为 Web 服务。

所有表单都是异步提交的,我在它们上使用 beforeSend 来附加我从元标记中获取的 CSRF 令牌,如下所示:

$.ajax({
    url: '/whatever/route',
    type: 'POST',
    dataType: 'JSON',
    data: $('form#whatever-form').serialize(),
    beforeSend: function(request) {
        return request.setRequestHeader('X-CSRF-Token', $("meta[name='token']").attr('content'));
    },
    success: function(response){
        rivets.bind($('#whateverTag'), {whateverData: response});
    },
    error: function(response){
    }
});

我的所有表单都可以正常工作,但 dropzone 上传却不行。它给了我一个TokenMismatchException 异常。这是我用于更新个人资料照片的 dropzone 代码:

$("#mydropzone").dropzone({
    url: "/profile/update-photo",
    addRemoveLinks : true,
    maxFilesize: 5,
    dictDefaultMessage: '<span class="text-center"><span class="font-lg visible-xs-block visible-sm-block visible-lg-block"><span class="font-lg"><i class="fa fa-caret-right text-danger"></i> Drop files <span class="font-xs">to upload</span></span><span>&nbsp&nbsp<h4 class="display-inline"> (Or Click)</h4></span>',
    dictResponseError: 'Error uploading file!'
});

我也尝试将beforeSend 放在这里:

$("#mydropzone").dropzone({
    url: "/profile/update-photo",
    addRemoveLinks : true,
    maxFilesize: 5,
    dictDefaultMessage: '<span class="text-center"><span class="font-lg visible-xs-block visible-sm-block visible-lg-block"><span class="font-lg"><i class="fa fa-caret-right text-danger"></i> Drop files <span class="font-xs">to upload</span></span><span>&nbsp&nbsp<h4 class="display-inline"> (Or Click)</h4></span>',
    dictResponseError: 'Error uploading file!',
    beforeSend: function(request) {
        return request.setRequestHeader('X-CSRF-Token', $("meta[name='token']").attr('content'));
    },
});

我还尝试在我的主文件中放置一个全局 ajaxSetup,如下所示:

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="token"]').attr('content')
    }
});

它仍然无法正常工作。我究竟做错了什么?如何通过 dropzone 上传在标头中传递 CSRF 令牌,以免出现异常?

【问题讨论】:

  • 您写了“Dropbox”,但我在您的问题中没有看到任何与 Dropbox 相关的内容。也许你的意思是说 Dropzone?我现在要删除 Dropbox 标签。
  • 感谢您通知我。我真是太愚蠢了。

标签: javascript laravel-5 csrf dropzone.js


【解决方案1】:

哇!惊人的反馈和建议!我对每条回复都做了一些处理,使其符合我的需要。

因此,让我将我现在使用 Flask-WTF 和“X-CSRF-Token”Dropzone Header 用于我的 FLASK 服务器的代码传递给它。

<form>
<div class="form-horizontal">
    <div class="upload-drop-zone" id="drop-zone-licenseKey">
        <div class="dz-message">
            Drag and Drop, or Click to<br> enter your new license key
        </div>
    </div>
    <script>
        var uploadLicenseKey = new Dropzone("div#drop-zone-licenseKey",{
        init: function() 
            {
                // Do Stuff
            },
        url: "/myLicenseURL",
        paramName: "myKey",
        maxFilesize: 1, //MB,
        maxFiles: 1,
        uploadMultiple: false,
        addRemoveLinks: true,
        autoProcessQueue: false, // do not upload until save is pressed
        acceptedFiles: ".txt",
        headers: { "X-CSRF-Token" : "{{ csrf_token() }}" }
        });
    </script>
</div>

【讨论】:

    【解决方案2】:

    其他答案似乎都没有指出你首先需要将meta标签添加到你的布局刀片文件中,大概是因为默认刀片布局文件有它,但为了便于参考,可以添加如下:

    <meta name="csrf-token" content="{{ csrf_token() }}">
    

    然后您可以在 Dropzone 调用的参数中引用 X-CSRF-TOKEN 标头:

    Dropzone.autoDiscover = false;
    jQuery(document).ready(function($) {
      $("div#uploader").dropzone({ 
            headers: { 
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }, 
            paramName: 'attachment', 
            url: "/upload/path"
      });
    });
    

    【讨论】:

      【解决方案3】:

      Django 解决方案(感谢@Rohan):

      headers: {
          'X-CSRFTOKEN': $('meta[name="token"]').context.cookie.split('=')[1]
      },
      

      【讨论】:

        【解决方案4】:

        对于那些来到这里并正在寻找 Rails 解决方案的人,请在标题中添加以下代码:

          headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
          },
        

        根据文档,这同样适用于 Laravel 6.x:https://laravel.com/docs/6.x/csrf#csrf-x-csrf-token

        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
        

        【讨论】:

          【解决方案5】:
          Dropzone.autoDiscover = false;
                  // or disable for specific dropzone:
                  // Dropzone.options.myDropzone = false;
          
                  $(function () {
                      // Now that the DOM is fully loaded, create the dropzone, and setup the
                      // event listeners
          
                      var myDropzone = new Dropzone("#my-awesome-dropzone");
                      myDropzone.on("addedfile", function (file) {
                          /* Maybe display some more file information on your page */
                      });
                      myDropzone.on("sending", function (file, xhr, formData) {
                           formData.append('csrfmiddlewaretoken', document.getElementsByName('csrfmiddlewaretoken')[0].value);
                          /* Maybe display some more file information on your page */
                      });
                  });
          

          你可以这样包含它。

          【讨论】:

            【解决方案6】:

            好的,这段代码现在可以正常工作了:

            $("#mydropzone").dropzone({
                url: "/profile/update-photo",
                addRemoveLinks : true,
                maxFilesize: 5,
                dictDefaultMessage: '<span class="text-center"><span class="font-lg visible-xs-block visible-sm-block visible-lg-block"><span class="font-lg"><i class="fa fa-caret-right text-danger"></i> Drop files <span class="font-xs">to upload</span></span><span>&nbsp&nbsp<h4 class="display-inline"> (Or Click)</h4></span>',
                dictResponseError: 'Error uploading file!',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="token"]').attr('content')
                }
            });
            

            所以基本上我需要在 Dropzone 请求的标头中添加X-CSRFToken。现在像魅力一样工作。

            【讨论】:

            • Dropzone 网站上的文档:dropzonejs.com/#config-headers
            • 只是想稍微澄清一下命名,默认的 Laravel 安装正在寻找'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')laravel.com/docs/5.5/csrf#csrf-x-csrf-token
            • 您能否编辑代码并将标头参数从X-CSRFToken 更改为X-CSRF-Token。新人可能会花费很多时间来弄清楚这一点。
            • 对于 Yii (PHP) 框架,当我在 Dropzone 配置中设置为 'X-CSRF-TOKEN''X-Csrf-Token' 并在服务器端读取为 $_SERVER['HTTP_X_CSRF_TOKEN'] 时,它可以工作。但是如果我在 Dropzone 配置中设置为'X_CSRF_TOKEN',它不会显示在服务器端。只是一个注释,而不是抱怨。
            【解决方案7】:
            you can add a headers.
            
            var myDropzone = new Dropzone("#drop_id", {
                url: "/upload/",
                headers: {'x-csrftoken': $.cookie('csrftoken')},
                method:"post",  
                ...
            }
            

            【讨论】:

            • 是的,这与 OP 自己发布并接受的解决方案相同
            【解决方案8】:

            这也很好用:

            $("#mydropzone").dropzone({
              url: "/profile/update-photo",
              addRemoveLinks : true,
              maxFilesize: 5,
              dictResponseError: 'Error uploading file!',
              headers: {
                'X-CSRF-Token': $('input[name="authenticity_token"]').val()
              }
            });
            

            【讨论】:

              【解决方案9】:

              对于使用默认 Laravel 设置的任何人:

              window.Laravel = {!! json_encode([
                  'csrfToken' => csrf_token(),
              ]) !!};
              
              Dropzone.options.attachments = {
                  url: 'upload',
                  headers: {
                      'X-CSRF-TOKEN': Laravel.csrfToken
                  }
              }
              

              【讨论】:

                【解决方案10】:

                我们可以在请求头中设置 CSRF 令牌。

                 xhr = open("POST",logURL,true);
                      //Set CSRF token in request header for prevent CSRF attack.
                 xhr.setRequestHeader(CSRFHeaderName, CSRFToken);

                【讨论】:

                  【解决方案11】:

                  我相信处理这个问题的最好方法是根据 Django 文档为所有 ajax 帖子(使用 jQuery)默认设置它

                  https://docs.djangoproject.com/en/1.8/ref/csrf/#ajax

                  function getCookie(name) {
                      var cookieValue = null;
                      if (document.cookie && document.cookie != '') {
                          var cookies = document.cookie.split(';');
                          for (var i = 0; i < cookies.length; i++) {
                              var cookie = jQuery.trim(cookies[i]);
                              // 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;
                  }
                  
                  var csrftoken = getCookie('csrftoken');
                  
                  function csrfSafeMethod(method) {
                      // these HTTP methods do not require CSRF protection
                      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
                  }
                  
                  function sameOrigin(url) {
                      // test that a given url is a same-origin URL
                      // url could be relative or scheme relative or absolute
                      var host = document.location.host; // host + port
                      var protocol = document.location.protocol;
                      var sr_origin = '//' + host;
                      var origin = protocol + sr_origin;
                      // Allow absolute or scheme relative URLs to same origin
                      return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                          (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                          // or any other URL that isn't scheme relative or absolute i.e relative.
                          !(/^(\/\/|http:|https:).*/.test(url));
                  }
                  
                  $.ajaxSetup({
                      beforeSend: function(xhr, settings) {
                          if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
                              // Send the token to same-origin, relative URLs only.
                              // Send the token only if the method warrants CSRF protection
                              // Using the CSRFToken value acquired earlier
                              xhr.setRequestHeader("X-CSRFToken", csrftoken);
                          }
                      }
                  });
                  

                  在您的示例中,将其添加到 Dropzone.js ajax 帖子时出现拼写错误。

                  'X-CSRF-Token'

                  应该是

                  'X-CSRFToken'

                  【讨论】:

                  • 将其设置为默认的 ajax 帖子会产生我稍后遇到的另一个问题。我试图使用第三方服务并卡住了,因为我无法理解错误是什么。后来我意识到,默认设置是向第三方发送 CSRF 令牌,这导致了问题。 :)
                  • 好点,值得记住!会说判断电话。如果您的代码中有更多的本地 ajax 调用,那么对远程调用进行异常处理可能更有意义,或者在相反的情况下反之。无论最终产生更少的工作。干杯!
                  【解决方案12】:

                  您可以使用这些代码为应用程序中的每个 jquery ajax 请求添加 csrf 令牌。

                  $.ajaxSetup({
                      headers: {
                          'X-CSRF-Token': $('meta[name="_token"]').attr('content')
                      }
                  });
                  

                  【讨论】:

                  • 根据the jQuery doc on this function,“不推荐使用它。”另外,我认为这可能只会影响通过 jQuery 库中的$.ajax() 进行的 AJAX 调用?
                  猜你喜欢
                  • 2017-01-18
                  • 2017-11-29
                  • 2017-10-10
                  • 2017-01-11
                  • 2018-03-17
                  • 1970-01-01
                  • 2018-03-20
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多