如何在 S3中存储数据,并允许用户使用 Rails API/iOS 客户端以安全的方式访问?

我刚开始编写 Rails 和 API。我需要一些关于 S3存储解决方案的帮助。这是我的问题。

我正在为一个 iOS 应用程序编写一个 API,用户可以用 iOS 上的 Facebook API 登录。服务器根据向 iOS 用户发出的令牌 Facebook 验证用户,并发出一个临时会话令牌。从这里开始,用户需要下载存储在 S3中的内容。此内容只属于用户及其朋友的子集。这个用户可以向 S3添加更多的内容,这些内容可以被同一群人访问。我想这就像把一个文件附加到一个 Facebook 群组..。

用户可以通过两种方式与 S3交互... ... 将其留给服务器或让服务器发出临时 S3令牌(不确定这里的可能性) ,用户可以直接访问到 S3的内容 URL。我发现这个问题谈论的方法,但是,它真的是过时的(2年前) : 关于从 iPhone 应用程序和 S3上传照片的架构和设计问题

那么问题来了:

  • 当发出临时令牌时,是否有方法限制用户只能访问 S3上的某些内容?我怎么能这么做?假设有... 比如说10万或更多的用户。
  • 让 iOS 设备直接把这些内容拉出来是个好主意吗?
  • 或者应该让服务器控制所有的内容传递(这当然解决了安全问题) ?这是否意味着我必须将所有内容下载到服务器,然后再将其传递给已连接的用户?
  • 如果你知道轨道... 我可以用回形针和 aws-sdk 宝石实现这种设置?

很抱歉问了你这么多问题,我很感激你对这个问题的洞察力。谢谢:)

72469 次浏览

Using the aws-sdk gem, you can get a temporary signed url for any S3 object by calling url_for:

s3 = AWS::S3.new(
:access_key_id => 1234,
:secret_access_key => abcd
)
object = s3.buckets['bucket'].objects['path/to/object']
object.url_for(:get, { :expires => 20.minutes.from_now, :secure => true }).to_s

This will give you a signed, temporary use URL for only that object in S3. It expires after 20 minutes (in this example), and it's only good for that one object.

If you have lots of objects the client needs, you'll need to issue lots of signed URLs.

Or should let the server control all content passing (this solves security of course)? Does this mean I have to download all content to server before handing it down to the connected users?

Note that this doesn't mean the server needs to download each object, it only needs to authenticate and authorize specific clients to access specific objects in S3.

API docs from Amazon: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth

The above answers use the old aws-sdk-v1 gem rather than the new aws-sdk-resources version 2.

The new way is:

aws_resource = Aws::S3::Resource::new
aws_resource.bucket('your_bucket').object('your_object_key').presigned_url(:get, expires_in: 1*20.minutes)

where your_object_key is the path to your file. If you need to look that up, you would use something like:

s3 = Aws::S3::Client::new
keys = []
s3.list_objects(bucket: 'your_bucket', prefix: 'your_path').contents.each { |e|
keys << e.key
}

That information was startlingly difficult to dig up, and I almost just gave up and used the older gem.

Reference

http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method