2015-04-20 7 views
5

Ich erstelle eine API für einen Back-End-Dienst mit Rails 4. Der Dienst muss eine Image-Datei in einen Amazon S3-Bucket hochladen.S3-Post-URL mit Abfrageparametern für einen mobilen Client abrufen

Ich möchte eine direkte Upload-URL verwenden, so dass die Clients die Uploads auf s3 verwalten und der Server nicht beschäftigt ist.

Derzeit habe ich folgende prototypische Aktion Schienen

def create 
    filename = params[:filename] 
    s3_direct_post = S3_BUCKET.presigned_post(key: "offers/#{SecureRandom.uuid}/#{filename}", acl: 'public-read') 
    s3p = s3_direct_post.fields 
    url = "#{s3_direct_post.url}/#{filename}?X-Amz-Algorithm=#{s3p['x-amz-algorithm']}&X-Amz-Credential=#{s3p['x-amz-credential']}&X-Amz-Date=#{s3p['x-amz-date']}&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=#{s3p['x-amz-signature']}" 
    render json: {success: true, url: url}, status: :ok 
end 

Dies erzeugt eine solche url:

https://my-bucket.s3.eu-central-1.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=MYKEY/20150420/eu-central-1/s3/aws4_request&X-Amz-Date=20150420T162603Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=MYSIGNATURE 

Jetzt versuche ich die test.png auf diese URL mit dem folgenden zu schreiben:

curl -v -T test.png "url"

und ich bekomme die folgenden ng Fehlerreaktion:

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>MYKEY</AWSAccessKeyId>... 

Ich glaube, das Problem kommt von der Tatsache, dass der angegebene X-Amz-SignedHeaders-Header falsch ist. Ich bin nicht sicher, welche Header standardmäßig von den Amazon Rails SDK Gem verwendet werden.

Wie sollte ich meine URL-Generation ändern, so dass ein mobiler Client einfach die URL nehmen und eine Datei an sie senden kann? Hier

Antwort

11

ist eine Lösung:

In config/initializers/aws.rb:

AWS_CREDS = Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY']) 

Aws.config.update({ 
    region: 'eu-central-1', 
    credentials: AWS_CREDS 
}) 

S3 = Aws::S3::Resource.new('eu-central-1') 
S3_BUCKET_NAME = ENV['S3_BUCKET_NAME'] 
S3_BUCKET = S3.bucket(S3_BUCKET_NAME) 

In Ihrem Modell/Steuerung/Sorge/oder was auch immer:

obj = S3_BUCKET.object("offers/#{user.id}/#{self.id}") 
url = obj.presigned_url(:put) # obj.presigned_url(:put, acl: 'public-read') #if you want to make the file public 

Dann Sie hochladen können eine Handy nutzen Kunde oder Locke:

curl -X PUT -T file_to_upload "url from above" 
Anmerkung 10

, dass Sie die x-amz-acl: public-read Header muss hinzufügen, wenn Sie die public-read acl Option:

curl -H "x-amz-acl: public-read" -X PUT -T file_to_upload "url from above" 
+1

'Ok niemand scheint über this' zu kümmern ... mit SO das ist so gut wie nie der Fall :) . Zum Zugriff auf meine serverseitig vordefinierten Post-Anmeldedaten von einem mobilen Client benötigt und war ein bisschen verwirrt, bis ich auf dieses stieß. Vielen Dank. – divergent

+1

Ja, das ist großartig. Ich möchte nur hinzufügen, dass, obwohl die Frage bezüglich aws-sdk Version 1 gestellt wurde, diese Lösung für aws-sdk Version 2 geeignet ist (beachten Sie, dass Aws :: S3 :: Resource.new in dieser Lösung * Aws *, nicht * AWS verwendet * - Version 2 des SDK verwendet * AWS * .Doks und Beispiele speziell für Version 2 SDK sind schwer zu bekommen, also danke dafür –

+0

Ich musste die Variablennamen von Großbuchstaben zu Großbuchstaben ändern, um eine Dynamik zu vermeiden Kontinuierlicher Zuweisungsfehler, jedoch –

Verwandte Themen