如何在Rails API / iOS客户端中将数据存储在S3中并允许用户安全访问?


93

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

我正在为iOS应用程序编写API,其中用户使用iOS上的Facebook API登录。服务器根据向iOS用户发出的Facebook令牌对用户进行验证,并发出临时Session令牌。从这一点上,用户需要下载存储在S3中的内容。此内容仅属于用户及其朋友的子集。该用户可以向S3添加更多内容,这些内容可以由同一群人访问。我想这类似于将文件附加到Facebook组...

用户可以通过2种方式与S3交互...将其留给服务器或让服务器发布临时S3令牌(不确定此处是否可行),并且用户可以直接访问S3的内容URL。我发现这个问题是关于方法的,但是它确实是过时的(两年前):关于从iPhone应用程序和S3上传照片的建筑和设计问题

所以问题:

  • 当发出临时令牌时,是否有办法限制用户只能访问S3上的某些内容?我怎样才能做到这一点?假设有...说100,000个或更多的用户。
  • 让iOS设备直接提取此内容是个好主意吗?
  • 还是应该让服务器控制所有传递的内容(这当然解决了安全性)?这是否意味着我必须将所有内容下载到服务器,然后再将其分发给已连接的用户?
  • 如果您知道rails ...我可以使用回形针和aws-sdk宝石来实现这种设置吗?

对于多个问题,我们深表歉意。对于任何对此问题的见解,我深表感谢。谢谢 :)


1
发现这个,我想我会为别人看评论docs.aws.amazon.com/AmazonS3/latest/dev/...
迪布尔

Answers:


113

使用aws-sdk gem,您可以通过调用url_for以下命令获取任何S3对象的临时签名URL :

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

这将为您提供S3中仅该对象的已签名的临时使用URL。它在20分钟后过期(在此示例中),并且仅对那个对象有效。

如果您有许多客户端需要的对象,则需要发布许多签名的URL。

还是应该让服务器控制所有传递的内容(这当然解决了安全性)?这是否意味着我必须将所有内容下载到服务器,然后再将其分发给已连接的用户?

请注意,这并不意味着服务器需要下载每个对象,它仅需要认证和授权特定客户端即可访问S3中的特定对象。

来自Amazon的API文档:https : //docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth


3
感谢@ejdyksen。我设计的解决方案正是使用了该解决方案(我还没有用答案更新问题)!因此,我的解决方案是为GET请求执行经过身份验证的URL。但是,当用户提供内容时,他将使用联合的IAM令牌(过期的临时凭据)以及附加的允许/ bucket / user / *写访问的策略,为特定的/ bucket / user / objectname位置创建资源。因此系统中的任何用户都不会损害其他用户的内容。似乎可以正常工作。感谢您的回答。
dineth 2012年

5
如果您使用的是aws-sdk-ruby的v2,请注意方法有些不同:docs.aws.amazon.com/sdkforruby/api/Aws/S3/…–
vijucat

2
用户看到我的访问密钥是否有风险?还有一个秘密密钥(已转换)
user2503775

3
@Dennis的全部要点是文件不必命中服务器。该链接不包含您的AWS凭证。它可能包含ACCESS_KEY_ID(我不记得我的头顶),但这并不是秘密。
ejdyksen '16

2
@ejdyksen,您是对的,我刚刚确认该URL仅包含AWS_ACCESS_KEY_ID。我本来以为AWS_SECRET_ACCESS_KEY也显示了,但没有显示。
丹尼斯

46

上面的答案使用旧的aws-sdk-v1 gem而不是新的aws-sdk-resources版本2。

新方法是:

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

其中your_object_key是文件的路径。如果需要查找,可以使用类似以下内容的方法:

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

收集这些信息非常困难,我几乎只是放弃并使用了较旧的宝石。

参考

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


1
expires_in期望以秒为单位的数据,只需确保先进行转换即可。
frillybob

“ ArgumentError(预期:expires_in为秒数)”
reedwolf
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.