使用安全方式上传COS并通过事件回调通知的实践
移动端文件上传是现在互联网应用架构中很常见的一种场景,在该场景中,往往会涉及到以下几个问题。
1.移动端权限控制
2.移动端传输效率
3.数据安全性
4.弹性扩容
5.成本
6.数据处理
本文介绍的“使用安全方式上传COS并通过事件回调通知”能够很好的解决以上6个问题。下面咱们看看如何实现的。
整体方案架构图如下。这里会用到3个主要的腾讯云产品,
腾讯云访问管理(Cloud Access Management,CAM)
腾讯云对象存储(Cloud Object Storage,COS)
腾讯云无服务器云函数(Serverless Cloud Function,SCF)
步骤1:由客户端向应用服务器发起请求。用于获取STS临时账号。
移动端调用DEMO代码可以参考COS官方文档https://cloud.tencent.com/document/product/436/9068
PC端调用DEMO代码可以参考COS官方文档https://cloud.tencent.com/document/product/436/9067
Q:这里需要通过中间的应用服务器来获取临时账号,为什么不用主账号和子帐号?
A:
- 主账号权限过大,可无限制操作所有的资源,非常不适合保存在客户端,有安全隐患。
- 子帐号虽然可以通过策略授权来限制权限范围。但如果保存到客户端后,不同的客户操作行为和资源不容易隔离,同时也没有时间控制,也不适合保存在客户端。
步骤2:应用服务器(Server端)接到客户端请求后,使用子帐号密钥向CAM服务发起临时账号申请。
Server端需要提供接口,用于客户端发起临时账号获取请求。而server端相对来说安全级别更高,可部署子帐号ID和密钥。子帐号默认具有STS获取权限。
多种语言(包括java,nodejs,php,python)获取STS的示例可参考
https://github.com/tencentyun/qcloud-cos-sts-sdk
需要注意的是,在申请STS时,我们需要赋予临时账号一定的权限,用于后续客户端操作COS来使用,例如我们这里设置的policy是
{
"statement": [{
"action": ["name/cos:GetObject", "name/cos:PutObject"],
"effect": "allow",
"resource": ["qcs::cos:ap-beijing:uid/1251956900:prefix//1251956900/sunweitest/*"]
}],
"version": "2.0"
}
拆分说明
action为“操作行为”,示例中包括了GetObject,PutObject,表示可以单文件下载对象和单文件上传对象。
更多COS API,请参考https://cloud.tencent.com/document/product/436/7751
effect为“效力”,示例中allow为允许行为,参数可选 ("allow" | "deny")
resource为“资源”
qcs:project_id:service_type:region:account:resource
- qcs:是 qcloud service 的简称,表示是腾讯云的云资源。该字段是必填项。
- project_id:描述项目信息,仅兼容 CAM 早期逻辑。当前策略语法禁止填写该信息。
- service_type:描述产品简称,如 CVM、CDN 等,产品的检测具体细节请参考对应的产品文档。值为
*
的时候表示所有产品。该字段是必填项。 - region:描述地域信息。值为空的时候表示所有地域。腾讯云新版地域统一命名方式请参考 地域和可用区。腾讯云现有的地域命名方式定义如下:
- account:描述资源拥有者的根账号信息。目前支持两种方式描述资源拥有者,uin 和 uid 方式。
- resource:描述各产品的具体资源详情。
示例中resource的含义就是,region资源为COS产品的北京园区,uid为1251956900,目录前缀为1251956900/sunweitest/ 下的所有资源。
policy的完整含义是允许对COS产品北京园区_UID为1251956900下且bucket为sunweitest的所有资源进行GetObject和PutObject_操作。
更详细的策略说明,请参考文档https://cloud.tencent.com/document/product/598/10603
步骤3:STS颁发临时账号ID,临时密钥,临时token。
调用请求示例:
https://sts.api.qcloud.com/v2/index.php?Action=GetFederationToken&Nonce=323820010&Region=gz&RequestClient=SDK_JAVA_1.3&SecretId=AKIDjNskW7UnqiO3aSLm9KKD0b1Rr8DQIP8k&Signature=zglPT6XJMkl1qzbcfNGUq48wFr0=&Timestamp=1558577532&name=1251956900&policy={"statement": [{"action": ["name/cos:GetObject","name/cos:PutObject"],"effect": "allow","resource":["qcs::cos:ap-beijing:uid/1251956900:prefix//1251956900/sunweitest/*"]}],"version": "2.0"}
STS返回成功示例:
{
"codeDesc": "Success",
"code": 0,
"data": {
"credentials": {
"tmpSecretId": "AKIDlFH1MtbCKv3pGzDoS5IYEMfoeCzk2vLD",
"tmpSecretKey": "BO04DXHPFjj4CKNSy2ECFSPrKm7M7anz",
"sessionToken": "5638d26115438d38e9137f5dfeceea2e9718431f30001"
},
"expiredTime": 1558579344
},
"message": ""
}
步骤4:应用服务器将临时账号ID,临时密钥,临时token等信息返给客户端
tmpSecretId:临时账号ID
tmpSecretKey:临时账号密钥
sessionToken:临时账号token
expiredTime:临时账号过期时间
备注:expiredTime过期或tmpSecretId错误会返回
The Access Key Id you provided does not exist in our records (Status Code: 403; Error Code: InvalidAccessKeyId)
步骤5:客户端使用临时账号ID,临时密钥,临时token向COS发起操作请求。
这里所做的操作权限,是和之前步骤2中设置的policy相关的。
我们这里用临时账号模拟做三个请求,分别是putobject,getobject,headobject。可以看到前两个可以执行,第三个报403无权限。符合预期。
步骤6:SCF监听COS的操作事件,符合条件则触发事件。
登录SCF控制台 https://console.cloud.tencent.com/scf
创建函数,例如创建一个php5的空白模板
示例函数代码如下
<?php
$gl = 1;
function main_handler($event, $context) {
$url1='http://xxxxxx.com/api?a=1&b=2';
//应用服务器调用入口
curl_file_get_contents($url1);
return "200 ok";
}
/*
* php访问url路径,get请求
*/
function curl_file_get_contents($durl){
// 初始化
$curl = curl_init();
// 设置url路径
curl_setopt($curl, CURLOPT_URL, $durl);
// 将 curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true) ;
// 在启用 CURLOPT_RETURNTRANSFER 时候将获取数据返回
curl_setopt($curl, CURLOPT_BINARYTRANSFER, true) ;
// 执行
$data = curl_exec($curl);
// 打印请求头信息
echo curl_getinfo($curl, CURLINFO_HEADER_OUT);
// 关闭连接
curl_close($curl);
// 返回数据
return $data;
}
?>
触发器设置,以下是可以触发COS事件的列表,值得注意的是,这里的触发时间都是操作事件完成后的触发,所以如果要对文件做处理,不用担心客户端操作时间差的问题。
步骤7:根据预先写好的事件处理程序,进行自定义业务处理,并将结果发送给应用服务器端。
触发事件后,验证是否成功。