¿Cómo almacenar datos en S3 y permitir el acceso de los usuarios de forma segura con los clientes API / iOS de rails?

Soy nuevo en la redacción de Rails y API. Necesito ayuda con la solución de almacenamiento S3. Aquí está mi problema.

Estoy escribiendo una API para una aplicación de iOS donde los usuarios inician sesión con la API de Facebook en iOS. El servidor valida al usuario contra el token de los problemas de Facebook para el usuario de iOS y emite un token de sesión temporal. A partir de este punto, el usuario debe descargar el contenido que está almacenado en S3. Este contenido solo le pertenece al usuario y a un subconjunto de sus amigos. Este usuario puede agregar más contenido a S3 al que puede acceder el mismo grupo de personas. Supongo que es similar a adjuntar un archivo a un grupo de Facebook …

Hay dos formas en las que un usuario puede interactuar con S3 … dejarlo en el servidor o hacer que el servidor emita un token S3 temporal (no estoy seguro de las posibilidades) y el usuario puede acceder a las URL de contenido directamente a S3. Encontré esta pregunta hablando de los enfoques, sin embargo, es realmente anticuada (hace 2 años): pregunta arquitectónica y de diseño sobre la carga de fotos desde la aplicación de iPhone y S3

Entonces las preguntas:

  • ¿Hay alguna forma de limitar que un usuario acceda solo a cierto contenido en S3 cuando se emite un token temporal? ¿Cómo puedo hacer esto? Supongamos que hay … digamos 100.000 o más usuarios.
  • ¿Es una buena idea dejar que el dispositivo iOS saque este contenido directamente?
  • ¿O debería dejar que el servidor controle todo el contenido que pasa (esto resuelve la seguridad, por supuesto)? ¿Esto significa que tengo que descargar todo el contenido al servidor antes de entregárselo a los usuarios conectados?
  • Si conoce los Rails … ¿puedo usar gemelos paperclip y aws-sdk para lograr este tipo de configuración?

Disculpas por las preguntas múltiples y agradezco cualquier idea sobre el problema. Gracias 🙂

Usando la gem aws-sdk , puede obtener una URL temporal firmada para cualquier objeto S3 llamando a 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 

Esto le dará una URL de uso temporal firmada solo para ese objeto en S3. Caduca después de 20 minutos (en este ejemplo), y solo es bueno para ese objeto.

Si tiene muchos objetos que el cliente necesita, deberá emitir muchas URL firmadas.

¿O debería dejar que el servidor controle todo el contenido que pasa (esto resuelve la seguridad, por supuesto)? ¿Esto significa que tengo que descargar todo el contenido al servidor antes de entregárselo a los usuarios conectados?

Tenga en cuenta que esto no significa que el servidor necesite descargar cada objeto, solo necesita autenticarse y autorizar a clientes específicos para acceder a objetos específicos en S3.

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

Las respuestas anteriores utilizan la antigua gem aws-sdk-v1 en lugar de la nueva versión 2 de aws-sdk-resources.

La nueva forma es:

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

donde your_object_key es la ruta a su archivo. Si necesita buscar eso, usaría algo como:

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

Esa información fue sorprendentemente difícil de desenterrar, y casi me rindo y utilicé la gem más antigua.

Referencia

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