web-dev-qa-db-fra.com

Comment stocker des données dans S3 et permettre l’accès des utilisateurs de manière sécurisée avec le client Rails API / iOS?)?

Je suis novice en écriture Rails et API. J'ai besoin d'aide avec la solution de stockage S3. Voici mon problème.

J'écris une API pour une application iOS où les utilisateurs se connectent à l'API Facebook sur iOS. Le serveur valide l'utilisateur par rapport au jeton. Facebook émet par l'utilisateur iOS et émet un jeton de session temporaire. À partir de ce moment, l'utilisateur doit télécharger le contenu stocké dans S3. Ce contenu n'appartient qu'à l'utilisateur et à un sous-ensemble de ses amis. Cet utilisateur peut ajouter plus de contenu à S3, qui peut être consulté par le même groupe de personnes. J'imagine que c'est similaire à attacher un fichier à un groupe Facebook ...

Il existe deux manières pour un utilisateur d'interagir avec S3 ... soit de laisser le serveur ou de lui demander d'émettre un jeton S3 temporaire (incertain des possibilités ici) et l'utilisateur peut accéder directement aux URL de contenu vers S3. J'ai trouvé cette question qui parle des approches, cependant, elle est vraiment datée (il y a 2 ans): Question d'architecture et de design sur le téléchargement de photos depuis une application iPhone et S

Alors les questions:

  • Existe-t-il un moyen de limiter l'accès d'un utilisateur à certains contenus sur S3 lorsqu'un jeton temporaire est émis? Comment puis-je faire ceci? Supposons qu'il y a ... disons 100 000 utilisateurs ou plus.
  • Est-ce une bonne idée de laisser le périphérique iOS extraire ce contenu directement?
  • Ou devrait-il laisser le serveur contrôler tout le contenu qui passe (cela résout bien sûr la sécurité)? Est-ce que cela signifie que je dois télécharger tout le contenu sur le serveur avant de le transmettre aux utilisateurs connectés?
  • Si vous connaissez Rails ... puis-je utiliser Paperclip et les gems aws-sdk pour réaliser ce type de configuration?

Toutes mes excuses pour les questions multiples et j'apprécie toute compréhension du problème. Merci :)

91
dineth

En utilisant aws-sdk gem , vous pouvez obtenir une URL signée temporaire pour tout objet S3 en appelant 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

Cela vous donnera une URL d'utilisation temporaire signée pour cet objet uniquement dans S3. Il expire après 20 minutes (dans cet exemple), et il ne convient que pour cet objet.

Si vous avez beaucoup d'objets dont le client a besoin, vous devrez générer beaucoup d'URL signées.

Ou devrait-il laisser le serveur contrôler tout le contenu qui passe (cela résout bien sûr la sécurité)? Est-ce que cela signifie que je dois télécharger tout le contenu sur le serveur avant de le transmettre aux utilisateurs connectés?

Notez que cela ne signifie pas que le serveur doit télécharger chaque objet, il doit seulement authentifier et autoriser des clients spécifiques à accéder à des objets spécifiques dans S3.

Documents de l'API d'Amazon: https://docs.aws.Amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth

113
ejdyksen

Les réponses ci-dessus utilisent l'ancienne gem aws-sdk-v1 plutôt que la nouvelle version 2 de aws-sdk-resources.

La nouvelle façon est:

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

où your_object_key est le chemin d'accès à votre fichier. Si vous devez rechercher cela, vous utiliserez quelque chose comme:

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

Cette information était étonnamment difficile à fouiller, et j'ai failli abandonner et utiliser le joyau le plus ancien.

Référence

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

45
chaqke