S3预签名URL上传文件返回403 Forbidden错误排查求助
问题排查与修复方案
1. 上传请求Body格式错误(核心原因)
生成预签名URL时指定的是put_object操作,该操作要求PUT请求直接上传原始文件内容,而非通过FormData包装。你的React代码用FormData.append('file', selectedFile)会在请求Body中添加multipart/form-data的边界信息,这和预签名时约定的ContentType(如image/jpeg)不匹配,导致S3签名验证失败,返回403。
修复后的React代码:
const uploadFile = async (signedUrl) => { try { const response = await fetch(signedUrl, { method: 'PUT', body: selectedFile, // 直接传入文件对象 headers: { 'Content-Type': selectedFile.type // 确保与预签名时的ContentType完全一致 } }); if (!response.ok) { throw new Error(`上传失败: ${response.statusText}`); } console.log('上传成功'); } catch (error) { console.error('上传错误:', error); } };
2. 桶策略中的占位符未替换
你提供的桶策略存在硬编码占位符,未替换为实际值,导致策略无法正确匹配IAM用户和存储桶:
Principal字段中的iamUsername需替换为实际创建的IAM用户名Resource字段中的bucketName需替换为实际的S3存储桶名称
修正后的桶策略示例:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::012345678901:user/你的实际IAM用户名" }, "Action": "s3:*", "Resource": [ "arn:aws:s3:::你的实际桶名", "arn:aws:s3:::你的实际桶名/*" ] } ] }
3. 冗余权限优化(可选)
你同时配置了IAM用户策略和桶策略,两者均授予s3:*权限。实际上只需其中一套配置即可,建议保留IAM用户策略(更符合权限最小化原则),可移除桶策略避免潜在的权限冲突。
额外验证步骤
- 确认预签名URL生成时的
ContentType与上传请求的Content-Type完全一致(包括大小写、参数等) - 验证IAM用户的访问密钥是否正确、未过期
- 确认S3存储桶的「阻止公共访问」配置仅限制公共访问,不影响预签名URL的正常使用(该配置本身不干预预签名请求)
内容的提问来源于stack exchange,提问作者Sid
相关产品推荐
相关产品推荐

