使用预签名 URL 上传到 S3 存储桶会出现 403 禁止错误

Kei*_*ris 5 amazon-s3 amazon-web-services pre-signed-url

我正在尝试使用 AWS S3 预签名 URL 为 Vue 应用程序实现图片上传功能。第一步是向 API 发送请求,该 API 将创建签名 URL 来上传文件。这部分工作正常:

服务器端:

'use strict';

const aws = require('aws-sdk');
const config = require('../config');
const util = require('./util');
const uuidv4 = require('uuid/v4');

const bucketName = 'myAmazonS3Bucket';

aws.config.update({
  secretAccessKey: config.AWS_SECRET_ACCESS_KEY,
  accessKeyId: config.AWS_ACCESS_KEY_ID,
  region: 'us-west-2'
});

const s3 = new aws.S3({ signatureVersion: 'v4' });

const handler = async (event) => {
    console.log('Uploading file...');

    return await getUploadURL();
}

const getUploadURL = async () => {
    const actionId = uuidv4();

    const s3Params = {
      Bucket: bucketName,
      Key:  `${actionId}.jpg`,
      ContentType: 'image/jpeg',
      ACL: 'public-read'
    };

    console.log(s3Params);

    return new Promise((resolve, reject) => {
        let uploadURL = s3.getSignedUrl('putObject', s3Params);

        console.log(uploadURL);

        resolve({
            "statusCode": 200,
            "isBase64Encoded": false,
            "headers": { "Access-Control-Allow-Origin": "*" },
            "body": JSON.stringify({
                "uploadURL": uploadURL,
                "photoFilename": `${actionId}.jpg`
            })
        });

        reject({
            "statusCode": 500,
            "headers": { "Access-Control-Allow-Origin": "*" },
            "body": "A funky error occurred and I am not happy about it!"
        })
    });
}

module.exports = {
    handler
}
Run Code Online (Sandbox Code Playgroud)

API 端点发送类似于此的响应:

{
    "uploadURL": "https://s3.us-west-2.amazonaws.com/pics.amazon-clone.io/7925d452-cadd-4f06-ba63-cc50645e3cfb.jpg?AWSAccessKeyId=AKIASGDJJ5ZLUVPMUYMQ&Content-Type=image%2Fjpeg&Expires=1580276753&Signature=3rqNckP4DiL6DkWPRuEGJsuIGpw%3D&x-amz-acl=public-read",
    "photoFilename": "7925d452-cadd-4f06-ba63-cc50645e3cfb.jpg"
}
Run Code Online (Sandbox Code Playgroud)

客户端将使用 uploadUrl 将文件上传到 S3 存储桶。这是客户端代码:

uploadImage: async function (e) {
            console.log('Upload clicked')
            console.log(e)

            // Get the presigned URL
            const response = await axios({
                method: 'POST',
                url: API_ENDPOINT
            })
            console.log('Response: ', response.data)
            console.log('Uploading: ', this.image)

            let binary = atob(this.image.split(',')[1])
            let array = []
            for (var i = 0; i < binary.length; i++) {
                array.push(binary.charCodeAt(i))
            }
            let blobData = new Blob([new Uint8Array(array)], {type: 'image/jpeg'})
            console.log('Uploading to: ', response.data.uploadURL)
            const result = await fetch(response.data.uploadURL, {
                method: 'PUT',
                headers: { 
                    'Content-Type': 'image/jpeg', 
                    'x-amz-acl': 'public-read' },
                body: blobData
            })
            console.log('Result: ', result)
            // Final URL for the user doesn't need the query string params
            this.uploadURL = response.data.uploadURL.split('?')[0]
        }
Run Code Online (Sandbox Code Playgroud)

不幸的是,我在使用签名 URL 时收到禁止的 403 错误。以下是我从 Chrome 浏览器收到的控制台错误的结果:

上传至: https: //s3.us-west-2.amazonaws.com/pics.amazon-clone.io/b1bdb5e3-7f64-49f7-b779-11b3f67317ee.jpg ?Content-Type=image%2Fjpeg&X-Amz-Algorithm =AWS4-HMAC-SHA256&X-Amz-凭证=AKIASGDJJ5ZLUVPMUYMQ%2F20200129%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20200129T165522Z&X-Amz-Expires=900&X-Amz-Signature=b230c9a4006 5585307e150655466bbab3d0d99aa43f8620377ab977eb1c7234c&X-Amz-SignedHeaders=主机%3Bx -amz-acl&x-amz-acl=公共读取

Pic.vue?937b:60 选项 https://s3.us-west-2.amazonaws.com/pics.amazon-clone.io/b1bdb5e3-7f64-49f7-b779-11b3f67317ee.jpg?Content-Type=image% 2Fjpeg&X-Amz-算法=AWS4-HMAC-SHA256&X-Amz-凭证=AKIASGDJJ5ZLUVPMUYMQ%2F20200129%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-日期=20200129T165522Z&X-Amz-Expires=900&X-Am z-签名=b230c9a40065585307e150655466bbab3d0d99aa43f8620377ab977eb1c7234c&X-Amz- SignedHeaders=host%3Bx-amz-acl&x-amz-acl=公共读取 403(禁止)

访问获取 ' https://s3.us-west-2.amazonaws.com/pics.amazon-clone.io/b1bdb5e3-7f64-49f7-b779-11b3f67317ee.jpg?Content-Type=image%2Fjpeg&X-Amz -算法=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASGDJJ5ZLUVPMUYMQ%2F20200129%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20200129T165522Z&X-Amz-Expires=900&X-Amz-Signature=b230c9 a40065585307e150655466bbab3d0d99aa43f8620377ab977eb1c7234c&X-Amz-SignedHeaders=主机%3Bx-amz-acl&x-amz-acl=public-read ' 来自原点 ' http://localhost:8080 ' 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:无 'Access-Control -Allow-Origin'标头存在于请求的资源上。如果不透明响应满足您的需求,请将请求模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。

小智 0

当您从 AWS S3 存储桶收到 OPTIONS -> CORS 策略错误时,这意味着您的存储桶配置不允许您上传图像。

要解决此问题,您必须更新存储桶的权限配置。

为此,请转到您的存储桶 -> 权限选项卡 -> CORS 选项卡

然后将以下代码放入其中:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin><YOUR_DOMAIN></AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Run Code Online (Sandbox Code Playgroud)

显然,不要忘记替换<YOUR_DOMAIN>为您的域名:P

If you want to allow all domains just replace this line

<AllowedOrigin><YOUR_DOMAIN></AllowedOrigin> 

with this

<AllowedOrigin>*</AllowedOrigin>
Run Code Online (Sandbox Code Playgroud)