【问题标题】:Direct to Amazon S3 Access Denied直接到 Amazon S3 访问被拒绝
【发布时间】:2014-01-17 10:20:14
【问题描述】:

我使用http://pjambet.github.io/blog/direct-upload-to-s3/ 作为教程。我已经启用了 CORS(请参阅 CORS 文件)。我得到 JSON 响应,这很好(在添加)文件上传查询功能。获取签名和策略后发生故障。尝试实际上传文件时,我收到来自 Amazon 的 Access Denied 错误。文件不上传。我错过了什么吗?

HTML:

<form class="file_upload" action="https://<% $AWSBUCKET %>.s3.amazonaws.com" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" />
<input type="hidden" name="policy" />
<input type="hidden" name="signature" />
<input type="hidden" name="AWSAccessKeyId" value="<% $AWSACCESS %>" />
<input type="hidden" name="acl" value="public-read" />
<input type="hidden" name="success_action_status" value="201" />

<div class="fileupload-content">
  <div class="fileupload-progress">
  </div>
</div>
<div class="file-upload">
  <span class="btn btn-success fileinput-button">
    <i class="glyphicon glyphicon-plus"></i>
    <span>Select files...</span>
    <input type="file" name="file" multiple>
  </span>
  <div class="progress progress-striped active">
    <div class="bar">
  </div>
</div>

Javascript:

$(function() {
  $('.file_upload').each(function() {
    var form = $(this)
    $(this).fileupload({
      url: form.attr('action'),
      type: 'POST',
      autoUpload: true,
      dataType: 'xml', // This is really important as s3 gives us back the url of the file in a XML document
      add: function (event, data) {
        $.ajax({
          url: "s3signed.html",
          type: 'GET',
          dataType: 'json',
          data: {filename: data.files[0].name, max_file_size : <% $MAX_FILE_SIZE %>}, // send the file name to the server so it can generate the key param
          async: false,
          success: function(data) {
            // Now that we have our data, we update the form so it contains all
            // the needed data to sign the request
            form.find('input[name=key]').val(data.key)
            form.find('input[name=policy]').val(data.policy)
            form.find('input[name=signature]').val(data.signature)
            console.log(data.key);
            console.log(data.policy);
            console.log(data.signature);
          }
        })
        data.submit();
      },
      send: function(e, data) {
        $('.progress').fadeIn();
      },
      progress: function(e, data){
        // This is what makes everything really cool, thanks to that callback
        // you can now update the progress bar based on the upload progress
        var percent = Math.round((e.loaded / e.total) * 100)
        $('.bar').css('width', percent + '%')
      },
      fail: function(e, data) {
        console.log('fail');
        console.log(data);
        console.log(e);
      },
      success: function(data) {
        // Here we get the file url on s3 in an xml doc
        var url = $(data).find('Location').text()

        $('#real_file_url').val(url) // Update the real input in the other form
      },
      done: function (event, data) {
        $('.progress').fadeOut(300, function() {
          $('.bar').css('width', 0)
        })
      },
    })
  })
});

Perl:

use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
use MIME::Base64;

use Data::Uniqid qw ( uniqid );
my $uniqid = uniqid;

my $key = "upload/$uniqid/$filename";
my $policy = s3PolicyDocument($AWSBUCKET, $max_file_size, $key);
my $signature = s3Signature($AWSSECRET, $policy);

my %response = (
  policy => $policy,
  signature => $signature,
  key => $key,
  success_action_status => 201
);

use JSON;
print JSON::encode_json(\%response);

sub s3PolicyDocument {
  my ($AWSBUCKET, $max_file_size, $key) = @_;
  use DateTime;
  my $dt = DateTime->now;
  $dt->add(minutes => 30);

  my $policy = '{"expiration": "'.$dt.'",
    "conditions": [ 
      {"bucket": "'.$AWSBUCKET.'"}, 
      {"acl": "public-read"},
      ["starts-with", "$key", ""],
      ["starts-with", "$Content-Type", ""],
      ["starts-with", "$name", ""],
      ["starts-with", "$Filename", ""],
      ["content-length-range", 0, '.$max_file_size.'],
      {"success_action_status": "201"},
    ]
  }';

  use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
  use MIME::Base64;


  $policy = encode_base64($policy);
  $policy =~ s/\n//g;
  return $policy;
}

sub s3Signature {
  my($AWSSECRET, $policy) = @_;
  my $signature = encode_base64(hmac_sha1($policy, $AWSSECRET));
  $signature =~ s/\n//g;
  return $signature;
}

CORS:

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

亚马逊回应:

<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>2448EA4E8E1F5377</RequestId>
<HostId>NlbqOAnjhPnqQLpaJRY1cVC6nFJ3ziVK+7ENrgILhA2njekXnp4mowv7jyTE2Z7K</HostId>
</Error>

【问题讨论】:

    标签: javascript perl amazon-s3 jquery-file-upload


    【解决方案1】:

    根据跨站点上传的文档,您应该使用forceIframeTransport 选项。

    $(this).fileupload({
        forceIframeTransport : true,
        ...
    });
    

    【讨论】:

    • 做到了!我不得不删除一些政策参数,但它的工作原理!
    • @RijviRajib 检查你的失败回调是否仍然有效,我听说过 Iframe Transport 的问题。
    • 是的,失败回调不起作用...我收到有效的上传响应,但请求失败。有什么补救办法吗?
    • @RijviRajib 目前这个问题没有答案,我正在寻找它:stackoverflow.com/questions/21176964/…
    • github.com/blueimp/jQuery-File-Upload/issues/2886 - 我想我不能为此使用 jQuery 文件上传。
    【解决方案2】:

    请按照以下步骤 去s3 您尝试访问的文件(使其公开可访问) 只需右键单击->公开

    这应该可以解决您的问题。

    【讨论】:

    • 文件上传失败。
    猜你喜欢
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    • 2016-10-08
    相关资源
    最近更新 更多