【问题标题】:Using S3 Presigned-URL for upload a file that will then have public-read access使用 S3 Presigned-URL 上传文件,该文件将具有公共读取访问权限
【发布时间】:2015-06-19 09:12:11
【问题描述】:

我正在使用 Ruby on Rails 和 AWS gem。 我可以获得用于上传和下载的预签名 URL。 但是当我得到 URL 时没有文件,因此将 acl 设置为“public-read” 在下载网址上不起作用。

用例是这样的:1,服务器为用户提供了一个将内容上传到我的存储桶的路径,没有凭据就无法读取。 2,并且该内容需要稍后公开:任何人都可以阅读。

澄清: 我没有上传文件,我正在提供 URL 供我的用户上传。当时我也想给用户一个公众可读的URL。如果我自己上传文件似乎会更容易。此外,读取 URL 需要永不过期。

【问题讨论】:

  • 更新:已修复。特雷弗非常有帮助。事实证明,我使用的是没有设置 PutWithACL 策略的 IAM 凭证。一旦我添加了它, put_url 就像 Trevor 在接受的答案中提到的那样工作。

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


【解决方案1】:

你有两个选择:

  • 在 PUT 对象时将对象上的 ACL 设置为“公共读取”。这允许您使用没有签名的公共 url 来获取对象。
  • 让对象上的 ACL 默认为私有,并为用户提供预签名的 GET url。这些过期,因此您必须根据需要生成新的 URL。预签名 URL 允许某人在没有凭据的情况下向对象发送 GET 请求。

上传公共对象并生成公共url:

require 'aws-sdk'

s3 = Aws::S3::Resource.new
s3.bucket('bucket-name').object('key').upload_file('/path/to/file', acl:'public-read')
s3.public_url
#=> "https://bucket-name.s3.amazonaws.com/key"

上传一个私有对象并生成一个1小时有效的GET url:

s3 = Aws::S3::Resource.new
s3.bucket('bucket-name').object('key').upload_file('/path/to/file')
s3.presigned_url(:get, expires_in: 3600)
#=> "https://bucket-name.s3.amazonaws.com/key?X-Amz-Algorithm=AWS4-HMAC-SHA256&..."

【讨论】:

  • 用例与您描述的有点不同。我没有上传文件,我正在提供 URL 供我的用户上传。当时我也想给用户一个公众可读的URL。如果我自己上传文件似乎会更容易。此外,读取 URL 需要永不过期。
【解决方案2】:

当您为 PUT 对象请求生成预签名 URL 时,您可以指定上传者必须使用的密钥和 ACL。如果我希望用户使用密钥“files/hello.txt”将对象上传到我的存储桶并且该文件应该是公开可读的,我可以执行以下操作:

s3 = Aws::S3::Resource.new
obj = s3.bucket('bucket-name').object('files/hello.text')

put_url = obj.presigned_url(:put, acl: 'public-read', expires_in: 3600 * 24)
#=> "https://bucket-name.s3.amazonaws.com/files/hello.text?X-Amz-..."

obj.public_url
#=> "https://bucket-name.s3.amazonaws.com/files/hello.text"

我可以将put_url 给其他人。此 URL 将允许他们将对象放入 URL。它具有以下条件:

  • PUT 请求必须在给定的到期期限内发出。在上面的示例中,我指定了 24 小时。 :expires_in 选项不得超过 1 周。
  • PUT 请求必须指定“x-amz-acl”的 HTTP 标头,其值为“public-read”。

使用put_url,我可以使用 Ruby 的 Net::HTTP: 上传任何对象:

require 'net/http'

uri = URI.parse(put_url)

request = Net::HTTP::Put.new(uri.request_uri, 'x-amz-acl' => 'public-read')
request.body = 'Hello World!'

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true   
resp = http.request(request)

现在对象已被其他人上传,我可以向#public_url 发出普通的 GET 请求。这可以通过浏览器、curl、wget 等来完成。

【讨论】:

  • 此外,还有一个预签名的 POST 实现供用户从浏览器上传对象。
  • 您链接到一个错误。该错误表明您的 CURL 命令发出了 GET 请求,而不是预期的 PUT 请求。我做了以下,它的工作: curl -H "x-amz-acl:public-read" https://..... -T upapp.txt
  • 这在 AWSSDK for C# 中不可用 - 有人知道如何在预签名 URL 生成期间指定 acl 参数吗?
  • 对于 C# 中的 AWSSDK,请参阅 github.com/aws/aws-sdk-net/issues/555
猜你喜欢
  • 2015-09-17
  • 2019-05-01
  • 2019-01-19
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
相关资源
最近更新 更多