问题
This problem has been driving me nuts for two days now.
The objective: Upload an image directly from the browser to S3 via a pre-signed URL supplied by the getSignedUrl function in the AWS Javascript SDK.
I haven't had any problems generating URLs with getSignedUrl. The following code...
const params = {
Key: key,
Bucket: process.env.S3_BUCKET,
ContentType: "image/jpeg"
};
S3.getSignedUrl("putObject", params, callback);
...yields something like:
https://s3.amazonaws.com/foobar-bucket/someImage.jpeg?AWSAccessKeyId=ACCESSKEY123&Content-Type=image%2Fjpeg&Expires=1543357053&Signature=3fgjyj7gpJiQvbIGhqWXSY40JUU%3D&x-amz-acl=private&x-amz-security-token=FQoGZXIvYXdzEDYaDPzeqKMbfgetCcZBaCL0AWftL%2BIT%2BP3tqTDVtNU1G8eC9sjl9unhwknrYvnEcrztfR9%2FO9AGD6VDiDDKfTQ9SmQpfXmiyTKDwAcevTwxeRnj6hGwnHgvzFVBzoslrB8MxrxjUpiI7NQW3oRMunbLskZ4LgvQYs8Rh%2FDjat4H%2F%2BvfPxDSQUSa41%2BFKcoySUHGh2xqfBFGCkHlIqVgk1KELDHmTaNckkvc9B4cgEXmAd3u1f1KC9mbobYcLLRPIzMj9bLJH%2BIlINylzubao1pCQ7m%2BWdX5xAZDhTSNwQfo4ywSWV7kUpbq2dgEriOiKAReEjmFQtuGqYBi3t2dhrasptOlXFXUozdz23wU%3D
But uploading an image via PUT request to the provided URL always returns a 403 SignatureDoesNotMatch
error from S3.
What DOES work:
- Calling getSignedUrl() from a local instance of AWS Lambda (via serverless-offline).
What DOESN'T work:
- Setting the query string variables as headers (Content-Type, x-amz-*, etc.)
- Removing all headers
- Changing the ACL when getting the URL (private, public-read-write, no ACL, etc.)
- Changing the region of
aws-sdk
in Node - Trying POST instead of PUT (it's worth a shot)
Any help on this issue would be greatly appreciated. I'm about to throw my computer out the window and jump out after it in frustration if this continues to be a problem, as it simply does NOT want to work!
回答1:
I figured it out. The Lambda function invoking getSignedUrl() did not have the correct IAM role permissions to access the S3 bucket in question. In serverless.yml...
iamRoleStatements:
- Effect: Allow
Action:
- s3:*
Resource: "arn:aws:s3:::foobar-bucket/*"
I wouldn't actually use a wildcard here, but you get the picture. The fact that getSignedUrl() still succeeds and returns a URL even when the URL is doomed to fail because of missing permissions is extremely misleading.
I hope this answer helps some confused soul in the future.
回答2:
It worked for me doing it in the old school way: (axios kept giving 403 Forbidden)
const xhr = new XMLHttpRequest();
xhr.open("PUT", signedRequest);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
//Put your logic here..
//When it get's here you can access the image using the url you got when signed.
}
}
};
xhr.send(file);
Notice this needs to run from the client, so you will need to configure the Cross Origin Police in your Bucket.
来源:https://stackoverflow.com/questions/53508691/aws-s3-put-to-url-from-getsignedurl-returns-403-signaturedoesnotmatch-error