使用Django API在Angular中展示AWS S3媒体对象遇403错误排查
问题背景
采用Django(PostgreSQL)后端+Angular前端架构,通过API获取的Post模型实例中,media字段存储Amazon S3桶内的图片URL。在Angular前端用img标签直接引用该URL时,出现403 Forbidden错误。
可能的遗漏配置点
1. 对象上传时的ACL未设置为公开可读
你的Django配置中AWS_DEFAULT_ACL = None,这会导致上传到S3的对象默认使用私有ACL。即使桶策略允许所有用户执行GetObject,若S3的Block Public Access中开启了相关ACL限制,对象的私有ACL会覆盖桶策略权限,触发403错误。
解决方法:修改Django的settings.py,二选一即可:
# 方法一:直接设置默认ACL为公开可读 AWS_DEFAULT_ACL = 'public-read' # 方法二:在对象参数中指定ACL AWS_S3_OBJECT_PARAMETERS = { 'StorageClass': 'STANDARD_IA', 'ACL': 'public-read' }
2. Block Public Access配置不完整
你仅取消了Block public access to buckets and objects granted through new public bucket or access point policies,但以下选项若开启也会导致403:
Block public access to buckets and objects granted through any access control lists (ACLs):会阻止所有通过ACL设置的公共访问Block public access to buckets and objects granted through new access control lists (ACLs):会阻止新的ACL公共访问设置Block all public access:会覆盖所有公共访问规则
解决方法:进入S3桶的权限设置,确认所有Block Public Access选项均已关闭(除非有特定安全需求)。
3. 桶策略的Resource路径与实际桶名不匹配
你的桶策略中Resource为arn:aws:s3:::socialpy-media-s3/*,但返回的图片URL中的<bucket-name>必须与该桶名完全一致,否则桶策略权限不会生效。
解决方法:修正桶策略的Resource为实际桶名:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::你的实际桶名/*" } ] }
4. S3签名版本或区域配置错误
若你的S3桶所在区域要求使用v4签名,而Django未配置正确,会导致请求被拒绝。
解决方法:在settings.py中添加签名版本配置,并确认区域正确:
AWS_S3_SIGNATURE_VERSION = 's3v4' # 确保此处为桶实际所在区域,例如ap-southeast-1、us-east-1等 AWS_REGION_NAME = config('AWS_REGION_NAME')
5. 浏览器缓存或CORS验证
虽然已配置CORS策略,仍可尝试:
- 清除浏览器缓存后重新加载页面
- 确认请求头中的Origin与CORS策略的
AllowedOrigins完全一致(例如是http://localhost:4200而非http://127.0.0.1:4200)
内容的提问来源于stack exchange,提问作者AbedDoesCode

