使用Ruby on Rails中的预签名URL上载到AWS S3

时间:2019-03-05 15:29:19

标签: ruby-on-rails ruby amazon-web-services amazon-s3

我需要从必须正确设置时钟的计算机上将文件上传到S3,并且与正确时间的偏差会有所不同。您显然可以通过指定X-Amz-Date标头(将其设置为当前实际时间)并使用查询字符串授权上载来实现。 aws-sdk Ruby宝石没有在其presigned_url方法中公开此参数,因此我尝试使用aws-sigv4宝石来实现。但是,我的PUT被拒绝,出现了403 Unauthorized错误。

这是我尝试过的代码:

def upload_file_with_time(file, file_path, expires_in_seconds, time)
  region = "us-east-1"
  access_key_id = ENV['AWS_ACCESS_KEY_ID']
  secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']

  obj = s3_bucket.object(file_path)

  signer = Aws::Sigv4::Signer.new(
    service: 's3',
    region: region,
    access_key_id: access_key_id,
    secret_access_key: secret_access_key
  )

  pre_signed_url = signer.presign_url(
    http_method: 'PUT',
    url: obj.public_url,
    expires_in: expires_in_seconds,
    time: time
  )

  Net::HTTP.start(pre_signed_url.host) do |http|
    http.send_request("PUT", pre_signed_url.request_uri, file, "content-type": "")
  end
end

代码会生成一个这样的预签名URL:

https://XXXXX.s3.amazonaws.com/testing/89254661-24de-4bc7-b6e1-7d0018213735.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXX%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190301T213824Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=XXXXX(敏感信息已用XXXXX编辑)。

当我尝试上传到此端点时,我从403 Unauthorized获得了http.send_request。如果我用来自curl的帖子打URL,我将其视为XML响应的开始:

<?xml version=“1.0”?>
<Error>
 <Code>SignatureDoesNotMatch</Code>
 <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>

我在做什么错了?

1 个答案:

答案 0 :(得分:0)

  

我需要从必须正确设置时钟的机器上将文件上传到S3。

时间是过去还是将来?尽管可能性很小,但这可能会引起问题(不过文档中没有显示相同的意思)。

但是,我发现您正在使用Net::HTTP软件包并发出原始PUT请求,并且您用于生成预签名URL的方法对我来说并不十分令人信服,因为obj.public_url的内容。

无论如何,我确实有这样的要求(预先上传URL,但没有“机器上的时间不正确”部分)。这是我使用并有效的指南:

https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjectPreSignedURLRubySDK.html

该页面上有一个有效的代码(不粘贴到这里,因为将来可能会更改)对我有用。