上传到 S3 时如何解决 403 Forbidden 错误

Posted

技术标签:

【中文标题】上传到 S3 时如何解决 403 Forbidden 错误【英文标题】:How to resolve 403 Forbidden error when uploading to S3 【发布时间】:2019-12-09 13:04:07 【问题描述】:

我正在建立一个 vuejs / DropzoneJS - 松散地基于 kfei 的 vue-s3-dropzone 应用程序的应用程序。它旨在使用 AWS Lambda 函数和 AWS S3 存储桶无服务器地将文件(通过使用 PUT 方法)上传到 AWS S3。我基本上是在来自源 'http://localhost:8080' 的'https://xxxxxxxxxxxxxxxxxxx' 处获取 XMLHttpRequest 已被阻止通过 CORS 策略:对预检请求的响应未通过访问控制检查:当我尝试将图像上传到 S3 存储桶时,它没有 HTTP ok 状态和 403 错误代码。有什么我可以做的吗

这就是我所做的:

    创建了一个 S3 存储桶

    在 S3 存储桶设置中设置存储桶策略和 CORS 配置:

    enter image description here enter image description here

    创建了一个 lambda 函数,该函数应该签署一个 URL,该 URL 允许将每个文件的 PUT 上传到 S3,执行 Lambda 的角色在 S3 存储桶上具有 PutObject 和 PutObjectAcl 权限:

    enter image description here

    使用 OPTIONS 方法(以通过预检检查)和使用这些 CORS 设置的 PUT 方法设置 Api Gateway API:

    b. OPTIONS 方法有一个 Mock 后端集成,集成响应返回以下内容:

    Access-Control-Allow-Headers 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,x-requested-with' 访问控制允许方法“PUT,OPTIONS” 访问控制允许来源'*'

    c。 PUT 方法有:

    “访问控制允许来源”:“*”

    在 AWS Api Gateway 中:设置 api-key 和使用计划

lambda 代码:

var AWS = require('aws-sdk');
var s3 = new AWS.S3();
var bucketName = process.env.AWS_BUCKET_NAME;

exports.handler = (event, context) => 
    if (!event.hasOwnProperty('contentType')) 
        context.fail( err: 'Missing contentType' );
    

    if (!event.hasOwnProperty('filePath')) 
        context.fail( err: 'Missing filePath' );
    

    var params = 
        Bucket: bucketName,
        Key: event.filePath,
        Expires: 3600,
        ContentType: event.contentType
    ;

    s3.getSignedUrl('putObject', params, (err, url) => 
        if (err) 
            context.fail( err );
         else 
            context.succeed( url );
        
    );
;

预期:文件上传成功 实际:可能的 CORS 问题。

【问题讨论】:

如果您看到 403 响应,则 S3 不会提供 cors 标头,您也会看到 cors 错误,问题出在权限上。 【参考方案1】:

getSignedUrl 如果您从 Postman 或 Node.js 服务器等 API 客户端上传文件,则可以正常工作,但正如您所说,您看到预检检查失败,我假设您正在使用某种 html 表单和前端 js。

来自AWS javascript SDK Docs 关于getSignedUrl:

注意:使用预签名时,并非所有操作参数都受支持 网址。某些参数,例如 SSECustomerKey、ACL、Expires、 发送内容时,必须将 ContentLength 或 Tagging 作为标头提供 要求。 如果您使用预签名 URL 从浏览器上传,并且 需要使用这些字段,请参见 createPresignedPost()

当您在调用 getSignedUrl 并从浏览器发送时设置“Expires”参数时,您需要在 Lambda 代码中使用 createPresignedPost 而不是 getSignedUrl。

然后您需要从浏览器向 S3 发送 POST 而不是 PUT。

注意:记得使用 POST 更新 S3 的 CORS 规则

【讨论】:

以上是关于上传到 S3 时如何解决 403 Forbidden 错误的主要内容,如果未能解决你的问题,请参考以下文章

使用签名 URL 上传到 S3 时出现 403(禁止)

为啥从浏览器上传到 S3 时出现 403 错误?

如何将 pdf 上传到 S3 存储桶?

使用 AWS CLI 上传到 S3 时如何设置 Content-Type?

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

尝试使用 PUT 将 PDF 作为 blob 上传到 S3 存储桶时被禁止 403