Jestem nowy w pisaniu Railsów i API. Potrzebuję pomocy z rozwiązaniem pamięci masowej S3. Oto mój problem.
Piszę API dla aplikacji iOS, w której użytkownicy logują się za pomocą Facebook API na iOS. Serwer weryfikuje użytkownika pod kątem tokena wystawionego przez Facebooka użytkownikowi iOS i wystawia tymczasowy token sesji. Od tego momentu użytkownik musi pobrać zawartość przechowywaną w S3. Ta treść należy tylko do użytkownika i części jego znajomych. Ten użytkownik może dodać więcej treści do S3, do których ma dostęp ta sama grupa osób. Wydaje mi się, że jest to podobne do dołączenia pliku do grupy na Facebooku ...
Istnieją 2 sposoby, w jakie użytkownik może wchodzić w interakcję z S3 ... pozostawić to serwerowi lub poprosić serwer o wydanie tymczasowego tokena S3 (nie jest pewien możliwości tutaj), a użytkownik może trafić na adresy URL treści bezpośrednio do S3. Znalazłem to pytanie, mówiąc o podejściach, jednak jest naprawdę przestarzałe (2 lata temu): Pytanie architektoniczne i projektowe dotyczące przesyłania zdjęć z aplikacji na iPhone'a i S3
Więc pytania:
- Czy istnieje sposób na ograniczenie dostępu użytkownika tylko do niektórych treści w S3, gdy zostanie wystawiony tymczasowy token? Jak mogę to zrobić? Załóżmy, że jest ... powiedzmy 100 000 lub więcej użytkowników.
- Czy dobrym pomysłem jest umożliwienie urządzeniu z systemem iOS bezpośredniego pobierania tej zawartości?
- A może powinien pozwolić serwerowi kontrolować wszystkie przekazywanie treści (to oczywiście rozwiązuje problem bezpieczeństwa)? Czy to oznacza, że muszę pobrać całą zawartość na serwer, zanim przekażę ją podłączonym użytkownikom?
- Jeśli znasz szyny ... czy mogę użyć spinacza i klejnotów aws-sdk, aby uzyskać taką konfigurację?
Przepraszam za wiele pytań i doceniam wszelkie wglądy w problem. Dzięki :)
Odpowiedzi:
Korzystając z klejnotu aws-sdk , możesz uzyskać tymczasowy podpisany adres URL dla dowolnego obiektu S3, wywołując
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
W ten sposób otrzymasz podpisany, tymczasowy adres URL tylko dla tego obiektu w S3. Wygasa po 20 minutach (w tym przykładzie) i nadaje się tylko do tego jednego obiektu.
Jeśli masz wiele obiektów, których potrzebuje klient, musisz wydać wiele podpisanych adresów URL.
Należy pamiętać, że nie oznacza to, że serwer musi pobrać każdy obiekt, musi jedynie uwierzytelnić i autoryzować określonych klientów w celu uzyskania dostępu do określonych obiektów w S3.
Dokumenty API z Amazon: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
źródło
ACCESS_KEY_ID
(nie pamiętam z czubka głowy), ale to nie ma być tajemnicą.AWS_ACCESS_KEY_ID
. Początkowo myślałem, żeAWS_SECRET_ACCESS_KEY
to też się wyświetla, ale tak nie jest.Powyższe odpowiedzi używają starego klejnotu aws-sdk-v1 zamiast nowej wersji 2 aws-sdk-resources.
Nowy sposób to:
aws_resource = Aws::S3::Resource::new aws_resource.bucket('your_bucket').object('your_object_key').presigned_url(:get, expires_in: 1*20.minutes)
gdzie twój_klucz_obiektu to ścieżka do twojego pliku. Jeśli chcesz to sprawdzić, użyj czegoś takiego:
s3 = Aws::S3::Client::new keys = [] s3.list_objects(bucket: 'your_bucket', prefix: 'your_path').contents.each { |e| keys << e.key }
Ta informacja była zaskakująco trudna do odkrycia, a ja prawie po prostu poddałem się i wykorzystałem starszy klejnot.
Odniesienie
http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method
źródło
expires_in
oczekuje danych w postaci sekund, po prostu upewnij się, że najpierw je przekonwertujesz.