¿Cómo almacenar datos en S3 y permitir el acceso del usuario de forma segura con rails API / iOS client?


Soy nuevo en la escritura de Rails y API. Necesito ayuda con la solución de almacenamiento S3. Este es mi problema.

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

Hay 2 maneras en que un usuario puede interactuar con S3... déjelo al servidor o haga que el servidor emita un token S3 temporal (no estoy seguro de las posibilidades aquí) y el usuario puede acceder a las URL de contenido directamente a S3. Encontré esta pregunta hablando de los enfoques, sin embargo, es realmente anticuado (hace 2 años): Pregunta de arquitectura y diseño sobre la carga fotos desde la aplicación iPhone y S3

Así que las preguntas:

  • ¿Hay alguna forma de limitar el acceso de un usuario solo a algunos contenidos 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 paso de contenido (esto resuelve la seguridad, por supuesto)? ¿Esto significa que tengo que descargar todo el contenido al servidor antes dando a los usuarios conectados?
  • Si conoces rails... ¿puedo usar paperclip y aws-sdk gems para lograr esta configuración?

Disculpas por múltiples preguntas y aprecio cualquier idea sobre el problema. Gracias :)

Author: Community, 2012-05-30

2 answers

Usando la gema aws-sdk , puede obtener una url firmada temporal para cualquier objeto S3 llamando 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, tendrá que emitir muchas URL firmadas.

O debe dejar que el servidor controle todo el paso de contenido (esto resuelve la seguridad de curso)? ¿Significa esto que tengo que descargar todo el contenido al servidor antes de entregarlo a los usuarios conectados?

Tenga en cuenta que esto no significa que el servidor necesite descargar cada objeto, solo necesita autenticar 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

 112
Author: ejdyksen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-19 16:11:12

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

El nuevo camino 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 necesitas buscar eso, usarías 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 di por vencido y usé la más antigua gema.

Referencia

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

 41
Author: chaqke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-15 00:41:14