使用generatePresignedPutUrl上传至Amazon S3返回Access Denied问题求助
问题诱因与解决方案
常见诱因及对应修复方法
- IAM账号缺少s3:PutObject权限
你用来生成预签名URL的Access Key对应的IAM身份(用户/角色),没有目标存储桶的s3:PutObject权限,属于最高发的诱因。
修复方法:给对应的IAM身份绑定如下权限策略,注意替换实际的存储桶ARN:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::atlasfitness-progress/*" } ] }
- 签名参数与实际上传请求参数不匹配
你的代码中generatePreSignedPutUrl方法接收了fileType参数,但没有将ContentType加入签名参数中。你用curl -T上传时,curl会自动根据文件类型添加Content-Type请求头,和签名时的参数不一致直接导致签名校验失败,返回AccessDenied。
修复方法:修改生成预签名URL的参数,补充ContentType字段:
const params = ({ Bucket: bucketName, Key: fileName, Expires: 1000, ContentType: fileType // 新增这一行 })
生成URL时传入正确的文件MIME类型(比如image/png),同时curl上传时也指定相同的Content-Type头,避免curl自动判断的类型和你传入的不一致:
curl -X PUT -T name_image -H "Content-Type: image/png" "url_generated_by_NodeJS_Code"
- 存储桶配置限制写入
你提到已经勾选了所有存储桶保护选项,检查以下配置:
- 存储桶的「阻止公共访问」配置如果开了全部选项,确认你的IAM身份是桶所有者或者有明确的写入权限,不会被公共访问规则拦截
- 存储桶策略有没有显式拒绝当前IAM身份的写入操作,或者限制了写入的IP、加密方式等条件
- 如果开了服务器端加密默认配置,需要确认签名时是否添加了对应的加密头参数(比如
x-amz-server-side-encryption)
- 基础配置校验不通过
确认以下配置项和实际值一致:
- 环境变量
AWS_REGION的值和存储桶实际所属的AWS区域完全一致 - 生成预签名URL后在有效期内使用(你设置的是1000秒,约16分钟,超时后需要重新生成)
- Access Key和Secret Key没有被禁用、过期,权限边界没有限制S3写入操作
内容的提问来源于stack exchange,提问作者Gonsa02
相关产品推荐
相关产品推荐

