Using S3 Presigned-URL for upload a file that will then have public-read access

前端 未结 2 1918
梦毁少年i
梦毁少年i 2021-01-04 09:20

I am using Ruby on Rails and AWS gem. I can get pre-signed URL for upload and download. But when I get the URL there is no file, and so setting acl to \'public-read\' on the

相关标签:
2条回答
  • 2021-01-04 10:05

    When you generate a pre-signed URL for a PUT object request, you can specify the key and the ACL the uploader must use. If I wanted the user to upload an objet to my bucket with the key "files/hello.txt" and the file should be publicly readable, I can do the following:

    s3 = Aws::S3::Resource.new
    obj = s3.bucket('bucket-name').object('files/hello.text')
    
    put_url = obj.presigned_url(:put, acl: 'public-read', expires_in: 3600 * 24)
    #=> "https://bucket-name.s3.amazonaws.com/files/hello.text?X-Amz-..."
    
    obj.public_url
    #=> "https://bucket-name.s3.amazonaws.com/files/hello.text"
    

    I can give the put_url to someone else. This URL will allow them to PUT an object to the URL. It has the following conditions:

    • The PUT request must be made within the given expiration. In the example above I specified 24 hours. The :expires_in option may not exceed 1 week.
    • The PUT request must specify the HTTP header of 'x-amz-acl' with the value of 'public-read'.

    Using the put_url, I can upload any an object using Ruby's Net::HTTP:

    require 'net/http'
    
    uri = URI.parse(put_url)
    
    request = Net::HTTP::Put.new(uri.request_uri, 'x-amz-acl' => 'public-read')
    request.body = 'Hello World!'
    
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true   
    resp = http.request(request)
    

    Now the object has been uploaded by someone else, I can make a vanilla GET request to the #public_url. This could be done by a browser, curl, wget, etc.

    0 讨论(0)
  • 2021-01-04 10:19

    You have two options:

    • Set the ACL on the object to 'public-read' when you PUT the object. This allows you to use the public url without a signature to GET the object.
    • Let the ACL on the object default to private and provide pre-signed GET urls for users. These expire, so you have to generate new URLs as needed. A pre-signed URL allows someone to send GET request to the object without credentials themselves.

    Upload a public object and generate a public url:

    require 'aws-sdk'
    
    s3 = Aws::S3::Resource.new
    s3.bucket('bucket-name').object('key').upload_file('/path/to/file', acl:'public-read')
    s3.public_url
    #=> "https://bucket-name.s3.amazonaws.com/key"
    

    Upload a private object and generate a GET url that is good for 1-hour:

    s3 = Aws::S3::Resource.new
    s3.bucket('bucket-name').object('key').upload_file('/path/to/file')
    s3.presigned_url(:get, expires_in: 3600)
    #=> "https://bucket-name.s3.amazonaws.com/key?X-Amz-Algorithm=AWS4-HMAC-SHA256&..."
    
    0 讨论(0)
提交回复
热议问题