不能让前端直接用后端AccessKey上传OSS,因会泄露主账号密钥;必须用STS临时凭证,由Flask调用aliyun-python-sdk-sts以RAM子用户AK/SK发起AssumeRole请求,返回含accessKeyId、accessKeySecret、securityToken的临时凭证供前端ali-oss SDK直传。

为什么不能让前端直接用后端的AccessKey上传OSS
因为把 AccessKeyId 和 AccessKeySecret 硬编码或透传给前端,等于公开了主账号密钥——哪怕加了Referer白名单,也能被爬虫抓包复用,权限失控风险极高。必须用临时凭证(STS Token)隔离权限,且限定 bucket、path、过期时间、操作类型。
Flask怎么生成合法的STS临时凭证(阿里云OSS场景)
要用阿里云官方 SDK aliyun-python-sdk-sts,不是自己拼签名。关键点是:必须用 RAM 子用户(非主账号)的 AK/SK 初始化客户端,并为该子用户授予最小化 sts:AssumeRole 权限(对应角色需提前在 RAM 控制台配置信任策略和权限策略)。
- 安装依赖:
pip install aliyun-python-sdk-core aliyun-python-sdk-sts - 角色 ARN 示例:
acs:ram::1234567890123456:role/oss-upload-role,需确保该角色允许被你的子用户扮演 - 调用
AssumeRoleRequest时,DurationSeconds建议设为 900–3600(15–60分钟),太长不安全,太短前端来不及传完大文件 - 返回的
Credentials包含AccessKeyId、AccessKeySecret、SecurityToken,三者缺一不可
from aliyunsdkcore.client import AcsClient
from aliyunsdksts.request.v20150401 import AssumeRoleRequest
<p>client = AcsClient('SUBUSER_AK', 'SUBUSER_SK', 'cn-hangzhou')
req = AssumeRoleRequest.AssumeRoleRequest()
req.set_RoleArn('acs:ram::1234567890123456:role/oss-upload-role')
req.set_RoleSessionName('flask-upload-session-' + str(int(time.time())))
req.set_DurationSeconds(1800)
res = client.do_action_with_exception(req)</p><h1>res 是 JSON 字符串,需 json.loads;注意捕获 ClientException / ServerException</h1><p>前端直传OSS需要哪些参数?后端要怎么塞进响应里
前端用 OSS 的 ali-oss SDK 直传,最少需要 5 个字段:region、bucket、accessKeyId、accessKeySecret、securityToken。别漏掉 securityToken —— 没它会报 InvalidToken 错误。
立即学习“Python免费学习笔记(深入)”;
-
region必须和 OSS bucket 所在地域一致(如oss-cn-hangzhou),不是 STS 接口的 region -
bucket必须明确指定,不能留空;若需按用户分目录,建议后端生成带前缀的dir(如user_123/),并限制 STS 角色 Policy 中的Resource为acs:oss:*:*:your-bucket/user_123/* - 响应体建议用 JSON,字段名保持和
ali-oss构造函数参数一致,避免前端二次映射出错
# Flask 路由示例
@app.route('/api/oss/sts', methods=['GET'])
def get_oss_sts():
# ... 上面的 AssumeRole 调用逻辑
data = json.loads(res)
return jsonify({
"region": "oss-cn-hangzhou",
"bucket": "my-app-bucket",
"accessKeyId": data["Credentials"]["AccessKeyId"],
"accessKeySecret": data["Credentials"]["AccessKeySecret"],
"securityToken": data["Credentials"]["SecurityToken"]
})
常见报错和绕不过去的坑
很多问题卡在 RAM 权限模型和 STS 签名链路上,和 Flask 关系不大,但排查时容易误判。
-
InvalidAccessKeyId:多半是用了主账号 AK,或子用户没开sts:AssumeRole权限 -
PolicyRestrictionViolation:STS 角色的权限策略太宽(比如允许*),阿里云会拒绝签发;必须显式声明oss:PutObject和资源路径 - 前端上传报
MissingSecurityToken:后端返回漏了securityToken,或前端初始化 client 时没传这个字段 - 上传成功但文件 0 字节:OSS 默认不自动处理表单上传的
key字段,前端必须用new OSS(...)实例调put()或multipartUpload(),别手写 POST 表单 - STS 凭证过期后前端还在用旧 token:前端应监听
onError,捕获ExpiredToken后重新请求/api/oss/sts
真正麻烦的从来不是 Flask 写几行代码,而是 RAM 角色、信任策略、权限策略三者之间的咬合关系——少配一条 Allow,整个链路就断在 STS 那一环,错误提示还极其模糊。
















