0

尝试从客户端上传时,我总是收到403。这是由于没有条件在桶上?如果我只是指定密钥 - 没有accesskey,签名或策略 - 它会正常上传。用rails,carrierwave-direct和jquery文件上传将文件上传到客户端的s3

桶政策:

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Sid": "AddPerm", 
      "Effect": "Allow", 
      "Principal": "*", 
      "Action": "s3:*", 
      "Resource": "arn:aws:s3:::example/*" 
     } 
    ] 
} 

CORS(开放由于是地方发展)

<?xml version="1.0" encoding="UTF-8"?> 
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 
    <CORSRule> 
     <AllowedOrigin>*</AllowedOrigin> 
     <AllowedMethod>GET</AllowedMethod> 
     <AllowedMethod>PUT</AllowedMethod> 
     <AllowedMethod>POST</AllowedMethod> 
     <AllowedMethod>DELETE</AllowedMethod> 
     <AllowedHeader>*</AllowedHeader> 
    </CORSRule> 
</CORSConfiguration> 

签名生成

///whats returned - in controller 

    string_to_sign 
    set_s3_direct_post(photo) 
    render :json => { 
     :policy => @policy, 
     :signature => sig, 
     :key => Rails.application.secrets.aws_access_key_id, 
     :success=>true, 
     :store=> photo.photo.store_dir, 
     :time => @time_policy, 
     :time_date => @date_stamp, 
     :form_data => @s3_direct_post 
    } 

------------------------------------------------------------------ 
    private 

    def string_to_sign 
    @time = Time.now.utc 
    @time_policy = @time.strftime('%Y%m%dT000000Z') 
    @date_stamp = @time.strftime('%Y%m%d') 

    ret = {"expiration" => 1.day.from_now.utc.xmlschema, 
      "conditions" => [ 
       {"bucket" => Rails.application.secrets.aws_bucket}, 
       {"x-amz-credential": "#{Rails.application.secrets.aws_access_key_id}/#{@date_stamp}/us-west-2/s3/aws4_request"}, 
       {"x-amz-algorithm": "AWS4-HMAC-SHA256"}, 
       {"x-amz-date": @time_policy }, 
      ] 
      } 

     @policy = Base64.encode64(ret.to_json).gsub(/\n/,'').gsub(/\r/,'') 

    end 

    def getSignatureKey 
     kDate = OpenSSL::HMAC.digest('sha256', ("AWS4" + Rails.application.secrets.aws_secret_access_key), @date_stamp) 
     kRegion = OpenSSL::HMAC.digest('sha256', kDate, 'us-west-2') 
     kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3') 
     kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request") 
    end 

    def sig 
     sig = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), getSignatureKey, @policy).gsub(/\n|\r/, '') 
    end 

客户:

var self=this; 
    $(`#song-upload`).fileupload({ 
     url: `https://${self._backend.BUCKET}.s3.amazonaws.com`, 
     dataType: 'json', 
     add: function (e, data) { 
      var data_add = data; 
      $.ajax({ 
      url: `${self._backend.SERVER_URL}/api/photo/new`, 
      data: {'authorization': `Bearer ${self._auth.isLoggedIn.getCookie('_auth')}`, post_type: 1, file_name:this.file_name}, 
      type: 'POST', 
      success: function(data) { 
       if(data.success){ 
       console.log(data); 
       self.key = data.key; 
       self.policy = data.policy; 
       self.signature = data.signature; 
       self.store_dir = data.store; 
       self.upload_time = data.time; 
       self.upload_date = data.time_date; 
       data_add.submit(); 
       } 
      } 
      }); 
     }, 
     submit: function (e, data) { 
      data.formData = {key:`${self.store_dir}/${self.file_name}`,AWSAccessKeyId: self.key, "Policy":self.policy, "x-amz-algorithm":"AWS4-HMAC-SHA256","Signature":self.signature,"x-amz-credential":`${self.key}/${self.upload_date}/us-west-2/s3/aws4_request`, "x-amz-date":self.upload_time}; 
     }, 
     progress: function (e, data) { 
      var progress = Math.floor(((parseInt(data.loaded)*0.9)/(parseInt(data.total))) * 100); 
      $('#inner-progress').css({'transform':`translateX(${progress}%)`}); 
      $('#progress-text').text(progress); 
     }, 
     done: function (e, data) { 
      $('#inner-progress').css({'transform':`translateX(100%)`}); 
      $('#progress-text').text(100); 
      if(e) console.log(e); 
     } 
    }); 
+0

我在过去做过。我正在关注Heroku的这篇文章。 https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails你也可以参考http://stackoverflow.com/a/34830257/3962760答案相同。 –

+0

刚达到文档。它看起来非常好。我会在早上通过它。谢谢。另外,你知道为什么s3允许我上传没有认证的文件吗?这是缺少的政策条件吗? –

+0

基本的东西是CORS设置和S3存储桶对象具有正确的凭据。如果这两件事情是适当的,那么你可以很容易地获得你的预先签名的URL。一旦你有了,那么没有其他认证需要。 –

回答

0

如果有人有这个,并且正在尝试做一个javascript上传,请尝试将值插入找到的here的html文件中。亚马逊会告诉你实际的错误,而不仅仅是一个403响应。

我错过了我的base64'd配置中的["starts-with", "$key", "uploads"]

这里是我的高端配置:

桶配置:

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Sid": "Allow Get", 
      "Effect": "Allow", 
      "Principal": "*", 
      "Action": "s3:GetObject", 
      "Resource": "arn:aws:s3:::example-development/*" 
     }, 
     { 
      "Sid": "AddPerm", 
      "Effect": "Allow", 
      "Principal": { 
       "AWS": "arn:aws:iam::123456789:user/example" 
      }, 
      "Action": "s3:*", 
      "Resource": ["arn:aws:s3:::example-development/*","arn:aws:s3:::example-development"] 
     } 
    ] 
} 

<?xml version="1.0" encoding="UTF-8"?> 
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> 
    <CORSRule> 
     <AllowedOrigin>*</AllowedOrigin> 
     <AllowedMethod>GET</AllowedMethod> 
     <AllowedMethod>PUT</AllowedMethod> 
     <AllowedMethod>POST</AllowedMethod> 
     <AllowedMethod>DELETE</AllowedMethod> 
     <AllowedHeader>*</AllowedHeader> 
    </CORSRule> 
</CORSConfiguration> 

后端:

 string_to_sign 
     set_s3_direct_post(song) 
     render :json => { 
       :policy => @policy, 
       :signature => sig, 
       :key => Rails.application.secrets.aws_access_key_id, 
       :success=>true, 
       :store=> song.song.store_dir, 
       :time => @time_policy, 
       :time_date => @date_stamp, 
       :form_data => @s3_direct_post 
     } 

def string_to_sign 

    @time = Time.now.utc 
    @time_policy = @time.strftime('%Y%m%dT000000Z') 
    @date_stamp = @time.strftime('%Y%m%d') 

    ret = {"expiration" => 10.hours.from_now.utc.iso8601, 
      "conditions" => [ 
       {"bucket" => 'waydope-development'}, 
       {"x-amz-credential": "#{Rails.application.secrets.aws_access_key_id}/#{@date_stamp}/us-west-2/s3/aws4_request"}, 
       {"x-amz-algorithm": "AWS4-HMAC-SHA256"}, 
       {"x-amz-date": @time_policy }, 
       ["starts-with", "$key", "uploads"] 
      ] 
      } 
    @policy = Base64.encode64(ret.to_json).gsub(/\n|\r/, '') 

end 

def getSignatureKey 
     kDate = OpenSSL::HMAC.digest('sha256', ("AWS4" + Rails.application.secrets.aws_secret_access_key), @date_stamp) 
     kRegion = OpenSSL::HMAC.digest('sha256', kDate, 'us-west-2') 
     kService = OpenSSL::HMAC.digest('sha256', kRegion, 's3') 
     kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request") 
    end 

def sig 
     # sig = Base64.encode64(OpenSSL::HMAC.digest('sha256', getSignatureKey, @policy)).gsub(/\n|\r/, '') 
     sig = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), getSignatureKey, @policy).gsub(/\n|\r/, '') 
end 

客户:

var self=this; 
    $(`#song-upload`).fileupload({ 
     url: `https://${self._backend.BUCKET}.s3.amazonaws.com`, 
     dataType: 'multipart/form-data', 
     add: function (e, data) { 
      var data_add = data; 
      $.ajax({ 
      url: `${self._backend.SERVER_URL}/api/music/new`, 
      data: {'authorization': `Bearer ${self._auth.isLoggedIn.getCookie('_waydope')}`, post_type: 1, file_name:this.file_name}, 
      type: 'POST', 
      success: function(data) { 
       if(data.success){ 
       console.log(data); 
       self.key = data.key; 
       self.policy = data.policy; 
       self.signature = data.signature; 
       self.store_dir = data.store; 
       self.upload_time = data.time; 
       self.upload_date = data.time_date; 
       data_add.submit(); 
       } 
      } 
      }); 
     }, 
     submit: function (e, data) { 
      data.formData = {key:`${self.store_dir}/${self.file_name}`, "Policy":self.policy,"X-Amz-Signature":self.signature,"X-Amz-Credential":`${self.key}/${self.upload_date}/us-west-2/s3/aws4_request`,"X-Amz-Algorithm":"AWS4-HMAC-SHA256", "X-Amz-Date":self.upload_time, "acl": "public-read"}; 
     }, 
     progress: function (e, data) { 
      var progress = Math.floor(((parseInt(data.loaded)*0.9)/(parseInt(data.total))) * 100); 
      $('#inner-progress').css({'transform':`translateX(${progress}%)`}); 
      $('#progress-text').text(progress); 
     }, 
     done: function (e, data) { 
      $('#inner-progress').css({'transform':`translateX(100%)`}); 
      $('#progress-text').text(100); 
      if(e) console.log(e); 
     } 
    }); 
+0

请注意,您无需手动生成所有这些AWS S3请求参数,只需使用官方的' aws-sdk'创业板为您生成它们:http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_post-instance_method –

+0

我可能刚刚使用它错误(或输入事情不正确),但从我所看到的情况来看,证书和政策并未从宝石中返回。 Heroku有一个关于使用浏览器上传的宝石的好的指导(https://devcenter.heroku.com/articles/direct-to-s3-image-uploads-in-rails) –

+1

我认为是这样,因为在'aws -sdk'版本2.7.11下面的代码片段返回'policy'和'x-amz-credential'参数:'Aws :: S3 :: Resource.new(access_key_id:“abc”,secret_access_key:“xyz”, region:“eu-west-1”)。bucket(“bucket”)。object(“foo”)。presigned_post.fields' –