直接拒绝Amazon S3 Access

时间:2014-01-17 10:20:14

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

我正在使用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>

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

请按照以下步骤操作 转到s3 您尝试访问的文件(公开可访问) 只需右击 - &gt;公开

这可以解决您的问题。