Làm cách nào để lưu trữ dữ liệu trong S3 và cho phép người dùng truy cập một cách an toàn với ứng dụng khách API / iOS rails?


93

Tôi mới viết Rails và API. Tôi cần một số trợ giúp với giải pháp lưu trữ S3. Đây là vấn đề của tôi.

Tôi đang viết một API cho một ứng dụng iOS trong đó người dùng đăng nhập bằng API Facebook trên iOS. Máy chủ xác thực người dùng chống lại sự cố mã thông báo Facebook đối với người dùng iOS và cấp mã thông báo Phiên tạm thời. Từ thời điểm này, người dùng cần tải xuống nội dung được lưu trữ trong S3. Nội dung này chỉ thuộc về người dùng và một nhóm nhỏ bạn bè của anh ta. Người dùng này có thể thêm nhiều nội dung hơn vào S3 mà cùng một nhóm người có thể truy cập. Tôi đoán nó tương tự như việc đính kèm một tệp vào một nhóm Facebook ...

Có 2 cách người dùng có thể tương tác với S3 ... để nó cho máy chủ hoặc yêu cầu máy chủ phát hành mã thông báo S3 tạm thời (không chắc chắn về khả năng ở đây) và người dùng có thể truy cập trực tiếp vào các URL nội dung tới S3. Tôi thấy câu hỏi này nói về các cách tiếp cận, tuy nhiên, nó thực sự đã lỗi thời (cách đây 2 năm): Câu hỏi về kiến ​​trúc và thiết kế về việc tải ảnh lên từ ứng dụng iPhone và S3

Vì vậy, các câu hỏi:

  • Có cách nào để giới hạn người dùng chỉ truy cập một số nội dung trên S3 khi mã thông báo tạm thời được phát hành không? Tôi có thể làm cái này như thế nào? Giả sử có ... 100.000 người dùng trở lên.
  • Bạn có nên để thiết bị iOS kéo trực tiếp nội dung này ra không?
  • Hoặc nên để máy chủ kiểm soát tất cả nội dung đi qua (điều này giải quyết vấn đề bảo mật tất nhiên)? Điều này có nghĩa là tôi phải tải tất cả nội dung xuống máy chủ trước khi chuyển cho người dùng được kết nối?
  • Nếu bạn biết đường ray ... tôi có thể sử dụng kẹp giấy và đá quý aws-sdk để đạt được thiết lập kinda này không?

Xin lỗi vì nhiều câu hỏi và tôi đánh giá cao mọi thông tin chi tiết về vấn đề. Cảm ơn :)


1
thấy điều này và nghĩ rằng tôi sẽ bình luận cho những người khác tìm docs.aws.amazon.com/AmazonS3/latest/dev/...
Dibble

Câu trả lời:


113

Sử dụng đá quý aws-sdk , bạn có thể nhận được một url được ký tạm thời cho bất kỳ đối tượng S3 nào bằng cách gọi 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

Điều này sẽ cung cấp cho bạn một URL sử dụng tạm thời, đã ký chỉ cho đối tượng đó trong S3. Nó hết hạn sau 20 phút (trong ví dụ này) và nó chỉ tốt cho một đối tượng đó.

Nếu bạn có nhiều đối tượng mà khách hàng cần, bạn sẽ cần phát hành nhiều URL đã ký.

Hoặc nên để máy chủ kiểm soát tất cả nội dung đi qua (điều này giải quyết vấn đề bảo mật tất nhiên)? Điều này có nghĩa là tôi phải tải tất cả nội dung xuống máy chủ trước khi chuyển cho người dùng được kết nối?

Lưu ý rằng điều này không có nghĩa là máy chủ cần tải từng đối tượng, nó chỉ cần xác thực và cho phép các máy khách cụ thể truy cập các đối tượng cụ thể trong S3.

Tài liệu API từ Amazon: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth


3
Cảm ơn vì điều đó @ejdyksen. Giải pháp tôi nghĩ ra đã sử dụng chính xác điều đó (Tôi chưa cập nhật câu hỏi với câu trả lời của mình)! Vì vậy, giải pháp của tôi là tạo URL được xác thực cho các yêu cầu GET. Tuy nhiên, khi người dùng đóng góp nội dung, anh ta sẽ tạo tài nguyên cho một vị trí / bucket / user / objectname cụ thể bằng cách sử dụng mã thông báo IAM được liên kết (thông tin xác thực tạm thời hết hạn) với chính sách được đính kèm để cho phép / bucket / user / * quyền ghi. vì vậy không người dùng nào trong hệ thống có thể gây hại cho nội dung của người dùng khác. Có vẻ hoạt động ổn. Đánh giá cao câu trả lời của bạn.
ăn tối

5
Nếu bạn đang sử dụng v2 của aws-sdk-ruby, hãy lưu ý rằng các phương pháp hơi khác nhau: docs.aws.amazon.com/sdkforruby/api/Aws/S3/…
vijucat

2
Người dùng có thể nhìn thấy khóa truy cập của tôi có phải là rủi ro không? Ngoài ra còn có các khóa bí mật (quy đổi)
user2503775

3
@Dennis toàn bộ điểm là tệp không cần phải truy cập vào máy chủ của bạn. Liên kết không chứa thông tin đăng nhập AWS của bạn. Nó có thể chứa ACCESS_KEY_ID(tôi không nhớ rõ), nhưng đó không phải là một bí mật.
ejdyksen 09-07-16

2
@ejdyksen bạn nói đúng, tôi vừa xác minh rằng URL chỉ chứa AWS_ACCESS_KEY_ID. Tôi ban đầu nghĩ rằng nó AWS_SECRET_ACCESS_KEYcũng được hiển thị nhưng nó không phải là.
Dennis

46

Các câu trả lời trên sử dụng đá quý aws-sdk-v1 cũ thay vì aws-sdk-resources phiên bản 2 mới.

Cách mới là:

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

trong đó your_object_key là đường dẫn đến tệp của bạn. Nếu bạn cần tra cứu, bạn sẽ sử dụng một cái gì đó như:

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

Thông tin đó thật khó khai thác và tôi gần như đã từ bỏ và sử dụng viên ngọc cũ hơn.

Tài liệu tham khảo

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


1
expires_inmong đợi dữ liệu ở dạng giây, chỉ cần đảm bảo chuyển đổi dữ liệu đó trước.
frillybob

"ArgumentError (dự kiến: expires_in là một số giây)"
reedwolf
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.