Как хранить данные в S3 и обеспечить безопасный доступ для пользователя с помощью rails API / iOS-клиента?

76

Я новичок в написании Rails и API. Мне нужна помощь в решении S3. Вот моя проблема.

Я пишу API для приложения iOS, где пользователи вступают в систему с API Facebook на iOS. Сервер проверяет пользователя на проблемы с токеном Facebook для пользователя iOS и выдает временный токен сеанса. С этого момента пользователю необходимо загрузить контент, который хранится в S3. Этот контент принадлежит только пользователю и подмножеству его друзей. Этот пользователь может добавить больше контента на S3, к которому можно получить доступ той же группой людей. Я думаю, это похоже на прикрепление файла к группе Facebook...

Существует два способа взаимодействия пользователя с S3: оставить его на сервере или заставить сервер выпустить временный токен S3 (не уверены в возможностях здесь), и пользователь может напрямую набирать URL-адреса контента к S3. Я нашел этот вопрос, говорящий о подходах, однако он действительно устарел (2 года назад): Архитектурный вопрос и вопрос о загрузке фотографий с iPhone-приложения и S3

Итак, вопросы:

  • Есть ли способ ограничить доступ пользователей к некоторому контенту на S3 при выдаче временного токена? Как я могу это сделать? Предположим, что есть... скажем, 100 000 или более пользователей.
  • Можно ли позволить устройству iOS напрямую вытащить этот контент?
  • Или должен ли сервер контролировать весь контент, проходящий (это, конечно, решает проблему)? Означает ли это, что мне нужно загрузить весь контент на сервер, прежде чем передавать его подключенным пользователям?
  • Если вы знаете рельсы... могу ли я использовать paperclip и aws-sdk gems для достижения этой настройки?

Извините за несколько вопросов, и я ценю любое понимание проблемы. Спасибо:)

Теги:
amazon-s3
amazon-ec2
client-server

2 ответа

99
Лучший ответ

Используя aws-sdk gem, вы можете получить временный подписанный URL-адрес для любого объекта S3, вызвав 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

Это даст вам подписанный, временный URL-адрес использования только для этого объекта в S3. Он истекает через 20 минут (в этом примере), и это полезно только для одного объекта.

Если у вас много объектов, которые нужны клиенту, вам нужно будет выпустить много подписанных URL-адресов.

Или должен позволить серверу управлять всем контентом (это, конечно, решает безопасность)? Означает ли это, что мне нужно загрузить весь контент на сервер, прежде чем передавать его подключенным пользователям?

Обратите внимание, что это не означает, что серверу необходимо загрузить каждый объект, ему нужно только аутентифицировать и авторизировать определенные клиенты для доступа к определенным объектам в S3.

API-документы от Amazon: http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth

  • 3
    Спасибо за это @ejdyksen. Решение, которое я разработал, использовало именно это (я не обновил вопрос своим ответом)! Поэтому я решил сделать аутентифицированные URL-адреса для запросов GET. Однако, когда пользователь добавляет контент, он создает ресурсы для определенного местоположения / bucket / user / objectname, используя федеративный токен IAM (временные учетные данные, срок действия которого истекает), с политикой, прикрепленной для разрешения доступа / bucket / user / * для записи. поэтому ни один пользователь в системе не может нанести вред контенту других пользователей. Кажется, работает хорошо. Ценю ваш ответ.
  • 1
    Это просто временный URL, а не один раз.
Показать ещё 6 комментариев
35

В приведенных выше ответах используется старый жемчуг aws-sdk-v1, а не новый 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

  • 0
    expires_in ожидает данные в виде секунд, просто убедитесь, что сначала преобразуйте их.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню