快速搭建移动应用传输服务
最近更新时间: 2024-10-17 17:10:00
背景
移动互联网时代,App 作为移动互联网服务的基础设施,往往需要上传和下载大量的数据,数据的安全性和可靠性尤为重要。现在开发者可以将数据存储相关的问题交给 云平台 COS 服务,而只需要关心自己应用的业务逻辑即可,可减少很多工作量,提升开发效率。
本文主要介绍如何快速搭建一个基于 COS 的应用传输服务,在云平台 COS 上实现应用数据的上传下载,在您的服务器上只需要部署您自己的业务、生成和管理临时密钥。
架构
整体架构图如下所示:
其中:
应用 APP:即用户手机上的 App。
COS:云平台对象存储,负责存储 App 上传的数据。
CAM:云平台访问管理,用于生成 COS 的临时密钥。
应用服务器:用户自己的后台服务器,这里用于向 CAM 请求临时密钥,并返回给应用 App。
步骤
应用向用户的应用服务器发送一个获取临时密钥的请求。 用户 App 在向 COS 发送请求时,必须通过密钥对请求进行签名。直接将用户的永久密钥放在终端上会存在很大的泄密风险,因此必须将您的永久密钥放在您的应用服务器上,然后由应用服务器向云平台 CAM 申请临时密钥,并最终返回给终端对请求进行签名。
应用服务器收到请求后,向 CAM 申请临时密钥。 我们认为用户的应用服务器是可信任的,可以直接配置用户的永久密钥用于向 CAM 申请临时密钥。同时,在服务端您可以配置临时密钥的有效期以及策略(Policy)。
CAM 返回临时密钥给应用服务器。
应用服务器返回临时密钥给应用 App。 我们对数据的返回格式没有做具体的要求,这里建议直接返回 CAM 的 JSON 数据即可。
应用 App 向 COS 发送请求(如上传文件等)。 应用 App 获取到临时密钥后,可以通过我们的 SDK 很容易地对请求进行签名,来使用我们的 COS 服务。
示例
搭建一个应用服务器
本示例采用 Python 编写,您可以 点击下载。
配置参数 下载并解压好的文件夹根目录下有
config.py
目录,可以来配置以下参数:class Config(object): def __init__(self): pass # 用户昵称,非必选 NAME = "WANG" # 策略 POLICY = COMMON_POLICY # 临时证书有效期 DURATION_SECOND = 1800 # 用户的secret id SECRET_ID = "您的 secret id" # 用户的secret key SECRET_KEY = "您的 secret key"
示例中提供的是一个拥有账户下所有资源读写权限的策略。
解析返回的 JSON 数据
{ "code":0,"message":"","codeDesc":"Success", "data": { "credentials": { "sessionToken":"42f8151428b3960b1226f421b8f271c6242ad02c3", "tmpSecretId":"AKIDtd9QSGWBIDuMaYFp57tSmrhJgohLtvpT", "tmpSecretKey":"ZfV5PVLvFLCvPefPt76qKYXIo56tSmrg" }, "expiredTime":1508400619 } }
应用服务器搭建临时密钥服务
下面以云平台 CVM Ubuntu 实例为例,详细介绍如何搭建一个简单的临时密钥服务。
登录云平台 CVM
购买 CVM 实例后,可直接用浏览器在控制台登录,或者使用终端直接 SSH 登录。
Ubuntu 环境下配置 Python 开发环境
sudo apt-get update sudo apt-get install python-dev python-pip python-virtualenv
下载源码并解压
wget http://rickenwang-1253653367.cosgz.myqcloud.com/resources/signer-release.zip unzip signer-release.zip ``` > 下载后直接解压,解压后需要修改根目录下的`secret_key`和`secret_id`配置信息,具体值可以在云 API 密钥控制台上查询。
激活 virtualenv 环境并进行配置
- 激活 virtualenv 环境:
cd 到flask项目目录 virtualenv venv source venv/bin/activate
- 配置环境:
pip install gunicorn pip install flask pip install flask-script
使用 supervisor 管理服务
- 安装 supervisor 并打开配置文件
pip install supervisor echo_supervisord_conf > supervisor.conf vi supervisor.conf
- 在配置文件
supervisor.conf
的底部添加以下内容:
[program:manage] command=./venv/bin/gunicorn -w4 -b0.0.0.0:5000 manage:app directory=./ startsecs=0 stopwaitsecs=0 autostart=false autorestart=false stdout_logfile=./log/gunicorn.log stderr_logfile=./log/gunicorn.err
启动服务并测试
使用如下命令启动服务:
supervisord -c supervisor.conf supervisorctl -c supervisor.conf start manage
应用服务器启动后,直接用浏览器访问
http://ip:5000/sign
地址,若返回临时密钥 JSON 字符串,则说明应用服务器临时密钥服务正常运行。
注意:
浏览器访问时 IP 请修改为您服务器的 IP 或者域名,默认的端口是 5000,您可自行在
supervisor.conf
文件中修改。
应用 App 接入应用服务器临时密钥服务
若您对云平台 COS 服务已有一些基本的了解,那么您可以很容易地使用我们 COS XML 终端 SDK,并将您的应用服务器的临时密钥服务接入进来,下面以 Android SDK 为例说明,总共分为三步:
注意:
使用我们的 SDK 前,您需要了解一些基本的名词术语,如 APPID、Bucket、SecretId、SecretKey 等。
1. 定义MySessionCredentialProvider
类继承抽象类BasicLifecycleCredentialProvider
,并实现其 fetchNewCredentials() 方法。
public class MySessionCredentialProvider extends BasicLifecycleCredentialProvider {
@Override
protected QCloudLifecycleCredentials fetchNewCredentials() throws QCloudClientException {
SessionQCloudCredentials credentials;
String tempSecretId = "";
String tempSecretKey = "";
String sessionToken = "";
long expireTime;
// 1、访问应用服务器获取临时密钥 API,获取临时密钥 JSON 字符串
// ...
// 2、解析 JSON 字符串,初始化 tempSecretId, tempSecretKey, sessionToken, expiredTime 四个参数
// ...
// 3、返回 SessionQCloudCredentials
return new SessionQCloudCredential(tempSecretId, tempSecreKey, sessionToken, expireTime);
}
}
2. 用MySessionCredentialProvider
初始化CosXmlService
。
// 您的账户信息
String appid = "对象存储 的服务APPID";
String region = "存储桶 所在的地域";
// 创建 CosXmlServiceConfig 对象
CosXmlServiceConfig serviceConfig = new CosXmlServiceConfig.Builder()
.setAppidAndRegion(appid, region)
.build();
// 初始化 CosXmlService
CosXmlService cosXmlService = new CosXmlService(getApplicationContext(), cosXmlServiceConfig,
new MySessionCredentialProvider());
3. 通过CosXmlService
对象的各种接口访问 COS 服务,下面以简单上传为例:
String bucket = "存储桶名称";
String cosPath = "远端路径,即存储到 COS 上的绝对路径"; //格式如 cosPath = "/test.txt";
String srcPath = "本地文件的绝对路径"; // 如 srcPath = Environment.getExternalStorageDirectory().getPath() + "/test.txt";
long signDuration = 600; //签名的有效期,单位为秒
PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, cosPath, srcPath);
putObjectRequest.setSign(signDuration,null,null);
/*
* 设置进度显示
* 实现 QCloudProgressListener.onProgress(long progress, long max) 方法,
* progress 已上传的大小, max 表示文件的总大小
*/
putObjectRequest.setProgressListener(new QCloudProgressListener() {
@Override
public void onProgress(long progress, long max) {
float result = (float) (progress * 100.0/max);
Log.w("TEST","progress =" + (long)result + "%");
}
});
//使用同步方法上传
try {
PutObjectResult putObjectResult = cosXmlService.putObject(putObjectRequest);
Log.w("TEST","success: " + putObjectResult.accessUrl);
} catch (CosXmlClientException e) {
//抛出异常
Log.w("TEST","CosXmlClientException =" + e.toString());
} catch (CosXmlServiceException e) {
//抛出异常
Log.w("TEST","CosXmlServiceException =" + e.toString());
}