web-dev-qa-db-ja.com

S3にデータを保存し、Rails AP​​I / iOSクライアントを使用して安全な方法でユーザーアクセスを許可する方法

RailsとAPIを書くのは初めてです。 S3ストレージソリューションに関するサポートが必要です。これが私の問題です。

ユーザーがiOSでFacebook APIを使用してログインするiOSアプリ用のAPIを作成しています。サーバーは、FacebookがiOSユーザーに発行するトークンに対してユーザーを検証し、一時的なセッショントークンを発行します。この時点から、ユーザーはS3に保存されているコンテンツをダウンロードする必要があります。このコンテンツは、ユーザーとその友人のサブセットのみに属します。このユーザーは、同じユーザーがアクセスできるコンテンツをS3に追加できます。 Facebookグループにファイルを添付するのに似ていると思います...

ユーザーがS3とやり取りする方法は2つあります。サーバーに任せるか、サーバーに一時的なS3トークンを発行してもらい(ここでの可能性は不明)、ユーザーはS3のコンテンツURLに直接アクセスできます。アプローチについて話しているこの質問を見つけましたが、実際には日付があります(2年前): iPhoneアプリとS3からの写真のアップロードに関する建築とデザインの質問

質問:

  • 一時トークンが発行されたときに、ユーザーがS3の一部のコンテンツのみにアクセスするように制限する方法はありますか?これどうやってするの?たとえば、100,000人以上のユーザーがいるとします。
  • IOSデバイスにこのコンテンツを直接引き出すことをお勧めしますか?
  • または、サーバーがすべてのコンテンツの受け渡しを制御できるようにする必要があります(これにより、もちろんセキュリティが解決されます)。これは、接続しているユーザーに渡す前に、すべてのコンテンツをサーバーにダウンロードする必要があるということですか?
  • Railsをご存知の場合は、Paperclipとaws-sdk gemを使用してこのようなセットアップを実現できますか?

複数の質問におApび申し上げます。問題に対する洞察に感謝します。ありがとう:)

91
dineth

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分後に期限切れになり、その1つのオブジェクトにのみ有効です。

クライアントが必要とするオブジェクトがたくさんある場合は、多くの署名付きURLを発行する必要があります。

または、サーバーがすべてのコンテンツの受け渡しを制御できるようにする必要があります(これにより、もちろんセキュリティが解決されます)。これは、接続しているユーザーに渡す前に、すべてのコンテンツをサーバーにダウンロードする必要があるということですか?

これは、サーバーが各オブジェクトをダウンロードする必要があるという意味ではなく、S3の特定のオブジェクトにアクセスするために特定のクライアントを認証および承認するだけでよいことに注意してください。

AmazonのAPIドキュメント: https://docs.aws.Amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth

113
ejdyksen

上記の回答では、新しいaws-sdk-resourcesバージョン2ではなく、古いaws-sdk-v1 gemを使用しています。

新しい方法は次のとおりです。

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

45
chaqke