APP的文件数据直传腾讯云COS实践

简介

本文主要介绍基于腾讯云对象存储COS,如何快速实现一个app的文件直传功能。您的服务器上只需要生成和管理访问密钥,无需关心细节,文件数据都存放在腾讯云 COS 上。

架构说明

对于app应用,把永久密钥放到客户端代码中,这既容易泄露您的密钥信息,也不便于控制用户访问权限。我们建议通过在请求时携带临时密钥,您可以临时授权您的 App 访问您的存储资源,而不会泄露您的永久密钥,密钥的有效期由您指定,过期后自动失效。

腾讯云COS 移动端 SDK(Android/IOS)均很好的支持了通过临时密钥来授权请求,您只需要在后台搭建一个临时密钥的服务,即可无缝给终端 COS 请求进行授权。

架构图

整体架构图如下所示:

其中:

用户客户端:即用户手机 App。

COS:腾讯云对象存储,负责存储 App 上传的数据。

CAM:腾讯云访问管理,用于生成 COS 的临时密钥。

用户服务端:用户自己的后台服务器,这里用于获取临时密钥,并返回给应用 App。

前提条件

创建存储桶。

COS 控制台上创建存储桶。按照您的需求,请将存储桶权限设置为私有读写或者公有读私有写。详细操作步骤请参见创建存储桶设置访问权限

获取永久密钥。

临时密钥需要通过永久密钥生成。请前往API 密钥管理获取 SecretId、SecretKey,前往账号信息获取 APPID。

注意:

目前腾讯云有COS特惠活动,新人1元起

实践步骤

搭建临时密钥服务

出于安全考虑,签名使用临时密钥,需要服务端搭建临时密钥服务,并提供 API 接口给客户端使用。具体搭建步骤请参见临时密钥生成及使用指引

注意:

正式部署时服务端请加一层您的网站本身的权限检验。

选择合适的权限

按照最小权限原则,建议您按照自己的需求,通过 Policy 控制临时密钥的权限范围。服务器下发一个完全读写权限的密钥,一旦被攻击,可能导致其他用户的数据泄露。具体的配置方法请参见临时密钥生成及使用指引。

SDK 接入授权服务

Android

搭建好临时密钥服务后,您需要将 SDK 接入到授权服务上,SDK 会负责控制请求的并发数,也会将有效的密钥缓存在本地,并在密钥失效之后重新再次请求,您无需管理获取的密钥。

标准响应体授权

如果您直接将 STS SDK 中得到的 JSON 数据作为临时密钥服务的响应体(cossign 即采用了这种方式),那么您可以使用如下代码来创建 COS SDK 中的授权类:


importandroid.content.Context;importcom.tencent.cos.xml.*;importcom.tencent.qcloud.core.auth.*;importcom.tencent.qcloud.core.common.*;importcom.tencent.qcloud.core.http.*;importjava.net.*;Contextcontext=...;CosXmlServiceConfigcosXmlServiceConfig=...;/**

* 获取授权服务的 url 地址

*/URLurl=null;// 后台授权服务的 url 地址try{    url =newURL("your_auth_server_url");}catch(MalformedURLException e) {    e.printStackTrace();}/** * 初始化 {@linkQCloudCredentialProvider} 对象,来给 SDK 提供临时密钥。 */QCloudCredentialProvidercredentialProvider=newSessionCredentialProvider(newHttpRequest.Builder()                .url(url)                .method("GET")                .build());CosXmlServicecosXmlService=newCosXmlService(context, cosXmlServiceConfig, credentialProvider);


说明:

这种方式下签名的开始时间为手机本地时间,因此如果手机本地时间偏差较大(十分钟以上),可能会导致签名出错,这种情况建议使用下述的自定义响应体授权。

自定义响应体授权

如果您想获得更大的灵活性,例如自定义临时密钥服务的 HTTP 响应体,给终端返回服务器时间作为签名的开始时间,用来避免由于用户手机本地时间偏差过大导致的签名不正确,或者使用其他的协议来进行终端和服务端之间的通信,那么您可以继承 BasicLifecycleCredentialProvider 类,并实现其 fetchNewCredentials():

请先定义一个 MyCredentialProvider 类:


importandroid.content.Context;importcom.tencent.cos.xml.*;importcom.tencent.qcloud.core.auth.*;importcom.tencent.qcloud.core.common.*;importcom.tencent.qcloud.core.http.*;importjava.net.*;publicclassMyCredentialProviderextendsBasicLifecycleCredentialProvider{@OverrideprotectedQCloudLifecycleCredentialsfetchNewCredentials()throwsQCloudClientException {// 首先从您的临时密钥服务器获取包含了签名信息的响应....// 然后解析响应,获取密钥信息StringtmpSecretId=...;StringtmpSecretKey=...;StringsessionToken=...;longexpiredTime=...;// 返回服务器时间作为签名的起始时间longbeginTime=...;// todo something you want// 最后返回临时密钥信息对象 returnnewSessionQCloudCredentials(tmpSecretId, tmpSecretKey, sessionToken, beginTime, expiredTime);    }}

利用您定义的 MyCredentialProvider 实例来授权请求:


importandroid.content.Context;importcom.tencent.cos.xml.*;importcom.tencent.qcloud.core.auth.*;importcom.tencent.qcloud.core.common.*;importcom.tencent.qcloud.core.http.*;importjava.net.*;Contextcontext=...;CosXmlServiceConfigcosXmlServiceConfig=...;/** * 初始化 {@linkQCloudCredentialProvider} 对象,来给 SDK 提供临时密钥。 */QCloudCredentialProvidercredentialProvider=newMyCredentialProvider();CosXmlServicecosXmlService=newCosXmlService(context, cosXmlServiceConfig, credentialProvider);


完整的示例代码请参见Android COS Transfer Practice

更多关于 Android 如何向 COS 上传和下载文件,请参见 Android SDK快速入门

iOS

我们提供了 QCloudCredentailFenceQueue 来方便地获取和管理临时签名。QCloudCredentailFenceQueue 提供了栅栏机制,也就是说您使用 QCloudCredentailFenceQueue 获取签名的话,所有需要获取签名的请求会等待签名完成后再执行,免去了自己管理异步过程。

使用 QCloudCredentailFenceQueue,我们需要先生成一个实例。



//AppDelegate.m//AppDelegate需遵循QCloudCredentailFenceQueueDelegate协议//- (BOOL)application:(UIApplication* )application didFinishLaunchingWithOptions:(NSDictionary* )launchOptions {// init stepself.credentialFenceQueue = [QCloudCredentailFenceQueue new];self.credentialFenceQueue.delegate =self;returnYES;}


然后调用 QCloudCredentailFenceQueue 的类需要遵循 QCloudCredentailFenceQueueDelegate 并实现协议内定义的方法:



-(void)fenceQueue:(QCloudCredentailFenceQueue * )queue requestCreatorWithContinue:(QCloudCredentailFenceQueueContinue)continueBlock


当通过 QCloudCredentailFenceQueue 去获取签名时,所有需要签名的 SDK 里的请求都会等待该协议定义的方法内拿到了签名所需的参数并生成有效的签名后执行。请看以下示例:


- (void)fenceQueue:(QCloudCredentailFenceQueue *)queue requestCreatorWithContinue:(QCloudCredentailFenceQueueContinue)continueBlock {    QCloudHTTPRequest* request = [QCloudHTTPRequest new];    request.requestData.serverURL = @“your sign service url”;//请求的URL[request setConfigureBlock:^(QCloudRequestSerializer *requestSerializer, QCloudResponseSerializer *responseSerializer) {        requestSerializer.serializerBlocks = @[QCloudURLFuseWithURLEncodeParamters];        responseSerializer.serializerBlocks = @[QCloudAcceptRespnseCodeBlock([NSSetsetWithObjects:@(200),nil],nil),//规定返回码是200以外的时候返回错误QCloudResponseJSONSerilizerBlock];//按照JSON格式解析返回的数据}];    [request setFinishBlock:^(idresponse,NSError*error) {if(error) {            error = [NSErrorerrorWithDomain:@"com.tac.test"code:-1111userInfo:@{NSLocalizedDescriptionKey:@"没有获取到临时密钥"}];            continueBlock(nil, error);        }else{            QCloudCredential* crendential = [[QCloudCredential alloc] init];            crendential.secretID = response[@"data"][@"credentials"][@"tmpSecretId"];            crendential.secretKey = response[@"data"][@"credentials"][@"tmpSecretKey"];            credential.startDate =[NSDatedateWithTimeIntervalSince1970:@"返回的服务器时间"]            crendential.experationDate = [NSDatedateWithTimeIntervalSinceNow:[response[@"data"][@"expiredTime"] intValue]];            crendential.token = response[@"data"][@"credentials"][@"sessionToken"];;            QCloudAuthentationV5Creator* creator = [[QCloudAuthentationV5Creator alloc] initWithCredential:crendential];            continueBlock(creator,nil);        }    }];    [[QCloudHTTPSessionManager shareClient] performRequest:request];}


更多关于 iOS 如何向 COS 上传和下载文件,请参见 iOS SDK快速入门

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容