s3.abortMultipartUpload error: Access denied

s3.abortMultipartUpload error: Access denied

我正在尝试建立一个上传机制来在 S3 上上传大文件,如果我愿意,也可以中止该过程。 下面是我上传文件的前端代码

html

<input  type="file"  id="multipartInput">
<button  id="multipartInputBtn">send file</button> 

JavaScript

document.getElementById('multipartInputBtn').addEventListener('click', async () => {
    const multipartInput_fileInput = document.getElementById('multipartInput');
    const file = multipartInput_fileInput.files[0];
    const fileName = file.name;
    const fileSize = file.size;
    const url = `https://uniquestring.execute-api.ap-south-1.amazonaws.com/dev`;

    try {
        let res = await axios.post(`${url}/getUploadId`, { fileName: fileName });   
        const uploadId = res.data.uploadId;
        console.log(res);
        console.log('Inside uploadMultipartFile');
        const chunkSize = 100 * 1024 * 1024; // 100MiB
        const chunkCount = Math.floor(fileSize / chunkSize) + 1;
        console.log(`chunkCount: ${chunkCount}`);

        let multiUploadArray = [];

        for (let uploadCount = 1; uploadCount < chunkCount + 1; uploadCount++) {
            let start = (uploadCount - 1) * chunkSize;
            let end = uploadCount * chunkSize;
            let fileBlob = uploadCount < chunkCount ? file.slice(start, end) : file.slice(start);

            let getSignedUrlRes = await axios.post(`${url}/getUploadPart`, {
                fileName: fileName,
                partNumber: uploadCount,
                uploadId: uploadId
            });
            let uploadChunck = await fetch(preSignedUrl, {
                method: 'PUT',
                body: fileBlob
            });
            console.log(uploadChunck);
            console.log(`preSignedUrl ${uploadCount} : ${preSignedUrl}`);
            console.log(fileBlob);
            // Start sending files to S3 part by part

            let uploadChunck = await axios.put(presignedUrl, fileBlob)  
            console.log(uploadChunck)
            

        }
        
    } catch (err) {
        console.log(err, err.stack);
    }
});

使用这种方法我可以上传文件,但是根据文档我尝试实现 abort multiPart Upload 我相应地实现了我的前端逻辑

前端

<button id="abortUploadBtn">Abort Upload</button>
document.getElementById('abortUploadBtn').addEventListener('click', () => {
    const multipartInput_fileInput = document.getElementById('multipartInput');
    const file = multipartInput_fileInput.files[0];
    const fileName = file.name;
    const uploadId = sessionStorage.getItem('uploadId');
    const url = `https://68qb5fre0e.execute-api.ap-south-1.amazonaws.com/dev`;
    console.log({ fileName: fileName, uploadId: uploadId });
    axios
        .post(`${url}/abortUpload`, { fileName: fileName, uploadId: uploadId })
        .then((r) => console.log(r))
        .catch((err) => console.error(err));
});

Lambda 后端

const AWS = require('aws-sdk');
const s3 = new AWS.S3({ signatureVersion: 'v4', region: 'ap-south-1' });
exports.handler = async (event) => {
    const body = JSON.parse(event.body);

    try {
        let params = {
            Bucket: process.env.bucketName,
            Key: body.fileName,
            UploadId: body.uploadId
        };
        const completeUpload = await s3.abortMultipartUpload(params).promise();
        return {
            statusCode: 200,
            headers: {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Credentials': true
            },
            body: JSON.stringify({ completeUpload: completeUpload })
        };
    } catch (err) {
        console.log(err);
        return {
            statusCode: 500,
            headers: {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Credentials': true
            },
            body: JSON.stringify({ error: err, details: err.stack })
        };
    }
};

导致我出现此 cloudwatch 错误

2021-03-11T11:51:43.367Z    58cba880-bbc2-4522-8c0f-8c73b2d3cd8f    INFO    AccessDenied: Access Denied
    at Request.extractError (/var/task/node_modules/aws-sdk/lib/services/s3.js:712:35)
    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:690:12)
    at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:116:18) {
  code: 'AccessDenied',
  region: null,
  time: 2021-03-11T11:51:43.363Z,
  requestId: 'BBF9AC13DD0C54FA',
  extendedRequestId: '/aQMS0mNmAEimuZ8nL0p+iDY9ndePTHU5fsfsnlbOH+anaWB4BOZH2bvVbn4wXefimH7gOh5za3U=',
  cfId: undefined,
  statusCode: 403,
  retryable: false,
  retryDelay: 5.35506042250955
}

但具有讽刺意味的是,如果我尝试在我的 PC 上本地严格使用文档中建议的方法(如下所述),它绝对可以正常工作

var params = {
  Bucket: "examplebucket", 
  Key: "bigobject", 
  UploadId: "xadcOB_7YPBOJuoFiQ9cz4P3Pe6FIZwO4f7wN93uHsNBEw97pl5eNwzExg0LAT2dUN91cOmrEQHDsP3WA60CEg--"
 };
 s3.abortMultipartUpload(params, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else     console.log(data);           // successful response
   /*
   data = {
   }
   */
 });

结果

{}

我应该怎么做才能完成这项工作?

编辑 我已附上我的 serverless.yml 以突出显示权限

provider:
  name: aws
  runtime: nodejs14.x
  lambdaHashingVersion: 20201221
  stage: dev
  region: ap-south-1
  apiGateway:
    shouldStartNameWithService: true
  iam:
    role:
      statements:
        - Effect: "Allow"
          Action:
            - "s3:GetObject"
            - "s3:PutObject"
          Resource: "arn:aws:s3:::${self:custom.bucketName}/*"
  environment:
    bucketName: ${self:custom.bucketName}   
provider:
  name: aws
  runtime: nodejs14.x
  lambdaHashingVersion: 20201221
  stage: dev
  region: ap-south-1
  apiGateway:
    shouldStartNameWithService: true
  iam:
    role:
      statements:
        - Effect: "Allow"
          Action:
            - "s3:GetObject"
            - "s3:PutObject"
            - "s3:AbortMultipartUpload"
          Resource: "arn:aws:s3:::${self:custom.bucketName}/*"
  environment:
    bucketName: ${self:custom.bucketName}  

你需要AbortMultipartUpload权限,我已经修改了上面模板中的调用。