使用临时安全凭证直传OBS
方案架构
使用的方式,可以将应用客户端的数据直传至OBS,或者将存储在OBS里的数据进行下载。具体流程如图1。
OBS支持使用临时安全凭证(临时AK/SK和securitytoken)进行授权访问,同时支持为临时安全凭证配置权限策略来指定使用该临时安全凭证时允许执行的操作。什么是临时安全凭证?
移动应用客户端可以使用指定了权限策略的临时安全凭证来访问OBS,实现数据直传,整个过程不会暴露用户的永久AK/SK,降低了账号泄露带来的安全风险。
角色分析如下:
- 应用客户端:即最终用户手机上的APP,负责向应用服务器发出申请临时安全凭证的请求,以及访问OBS完成数据上传或下载。
- 应用服务器:即提供该Android/iOS应用的开发者开发的APP后台服务,用于用户管理和授权管理等。
- 对象存储服务:即华为云对象存储服务,负责处理移动应用的数据请求。
- 统一身份认证服务:即华为云统一身份认证服务,负责生成临时安全凭证。
实现流程如下:
- 应用客户端向应用服务器申请一个临时操作凭证。
- 应用服务器向统一身份认证服务请求临时安全凭证。
- 统一身份认证服务向应用服务器返回临时安全凭证。
- 应用服务器将临时安全凭证发放给应用客户端。
- 应用客户端使用安全凭证完成OBS数据上传下载。
资源和成本规划
最佳实践中涉及的资源如下:
资源 |
资源说明 |
---|---|
应用客户端(APP Client) |
最终用户手机上的APP,负责向应用服务器发出申请临时安全凭证的请求,以及访问OBS完成数据上传或下载。 |
应用服务器(APP Server) |
提供该Android/iOS应用的开发者开发的APP后台服务,用于用户管理和授权管理等。 |
对象存储服务(OBS) |
华为云对象存储服务,负责处理移动应用的数据请求。 |
统一身份认证服务(IAM) |
华为云统一身份认证服务,负责生成临时安全凭证。 |
实施步骤
- 获取OBS SDK开发包和IAM SDK开发包。
OBS SDK请在SDK开发指南中获取。
IAM SDK开发包请在IAM开发工具包获取。
- 模拟应用服务器向IAM请求临时安全凭证和返回安全凭证。
过程如下:
- 获取用户的IAM用户Token。
API请参见获取IAM用户Token(使用密码),SDK请参见SDK中心。
- 使用Token获取临时安全凭证(临时AK/SK和securitytoken),获取时需要通过Policy字段指定该安全凭证允许执行的操作权限。
API请参见通过token获取临时访问密钥和securitytoken,SDK请参见SDK中心。
示例:获取一个有效期为900秒的临时安全凭证,该凭证只允许上传数据到桶hi-company的APPClient/APP-1/目录下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
{ "auth":{ "identity":{ "policy":{ "Version":"1.1", "Statement":[ { "Action":[ "obs:object:PutObject" ], "Resource":[ "obs:*:*:object:hi-company/APPClient/APP-1/*" ], "Effect":"Allow" } ] }, "token":{ "duration-seconds":900, "id":"MIIDkgYJKoZIhvcNAQcCoIIDgzCCA38CAQExDTALMEXXXXX..." }, "methods":[ "token" ] } } }
- 获取用户的IAM用户Token。
- 初始化应用客户端中OBS client。
初始化示例:
- Android
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
String endPoint = "https://your-endpoint"; // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量ACCESS_KEY_ID和SECRET_ACCESS_KEY_ID。 // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html String ak = System.getenv("ACCESS_KEY_ID"); String sk = System.getenv("SECRET_ACCESS_KEY_ID"); String token = System.getenv("Security_Token"); // 创建ObsConfiguration配置类实例 ObsConfiguration config = new ObsConfiguration(); config.setEndPoint(endPoint); config.setSocketTimeout(30000); config.setConnectionTimeout(10000); // 创建ObsClient实例 ObsClient obsClient = new ObsClient(ak, sk,token,config); // 使用访问OBS // 关闭obsClient obsClient.close();
- endPoint即终端节点,可通过地区和终端节点查询。
- ak和sk即临时AK/SK,token即securitytoken,获取方式请参见访问密钥(AK/SK)。
- iOS
1 2 3 4 5 6 7 8 9 10 11 12
NSString *endPoint = @"your-endpoint"; // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量AccessKeyID和SecretAccessKey。 // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html NSString *SK = getenv("AccessKeyID"); NSString *AK = getenv("SecretAccessKey"); // 初始化身份验证 OBSStaticCredentialProvider *credentailProvider = [[OBSStaticCredentialProvider alloc] initWithAccessKey:AK secretKey:SK]; securityTokencredentailProvider.securityToken = @"*** Provide your Security Token ***"; // 初始化服务配置 OBSServiceConfiguration *conf = [[OBSServiceConfiguration alloc] initWithURLString:endPoint credentialProvider:credentialProvider]; // 初始化 clientOBSClient *client = [[OBSClient alloc] initWithConfiguration:conf];
- endPoint即终端节点,可通过地区和终端节点查询。
- ak和sk即临时AK/SK,token即securitytoken,获取方式请参见访问密钥(AK/SK)。
- web js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// 未引入AMD,直接通过构造函数创建ObsClient实例 var obsClient = new ObsClient({ // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量AccessKeyID和SecretAccessKey。 // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html access_key_id: process.env.AccessKeyID, secret_access_key: process.env.SecretAccessKey, security_token: process.env.SecurityToken, server : 'https://your-endpoint' }); // 使用访问OBS // 引入AMD,通过依赖注入的构造函数创建ObsClient实例 var obsClient; define(['ObsClient'], function(ObsClient){ obsClient = new ObsClient({ // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量AccessKeyID和SecretAccessKey。 // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html access_key_id: process.env.AccessKeyID, secret_access_key: process.env.SecretAccessKey, security_token: process.env.SecurityToken, server : 'https://your-endpoint' }); // 使用访问OBS });
- endPoint即终端节点,可通过地区和终端节点查询。
- ak和sk即临时AK/SK,token即securitytoken,获取方式请参见访问密钥(AK/SK)。
- Android
- 使用临时安全凭证完成OBS数据上传下载,示例如下。
- Android
// obsClient 是步骤3创建的ObsClient实例 // 流式上传 String content = "Hello OBS"; obsClient.putObject("bucketname", "objectname", new ByteArrayInputStream(content.getBytes())); // 流式下载 ObsObject obsObject = obsClient.getObject("bucketname", "objectname"); // 读取对象内容 Log.i("GetObject", "Object content:"); InputStream input = obsObject.getObjectContent(); byte[] b = newbyte[1024]; ByteArrayOutputStream bos = new ByteArrayOutputStream(); int len; while ((len=input.read(b)) != -1){ bos.write(b, 0, len); } Log.i("GetObject", new String(bos.toByteArray())); bos.close(); input.close();
- iOS
// obsClient 是步骤3创建的ObsClient实例 // 流式上传 OBSPutObjectWithDataRequest *request = [[OBSPutObjectWithDataRequest alloc]initWithBucketName:@"bucketname" objectKey:@"objectname" uploadData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]]; // 流式下载 OBSGetObjectToDataRequest *request = [[OBSGetObjectToDataRequest alloc]initWithBucketName:@"bucketname" objectKey:@"objectname"]; // 下载进度 request.downloadProgressBlock = ^(int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) { NSLog(@"%0.1f%%",(float)(totalBytesWritten)*100/(float)totalBytesExpectedToWrite); }; // 下载的数据 __block NSMutableData *objectData = [NSMutableData new]; request.onReceiveDataBlock = ^(NSData *data) { [objectData appendData:data]; }; // 下载结果 [client getObject:request completionHandler:^(OBSGetObjectResponse *response, NSError *error){ NSLog(@"%@",response); }] ;
- web js
// obsClient 是步骤3创建的ObsClient实例 // 文本上传 obsClient.putObject({ //使用Body参数指定待上传的字符串。 Bucket: 'bucketname', Key: 'objectname', Body: 'Hello OBS' }, function (err, result) { if(err){ console.error('Error-->' + err); }else{ console.log('Status-->' + result.CommonMsg.Status); } }); // 文本下载 obsClient.getObject({ Bucket : 'bucketname', Key : 'objectname' }, function (err, result) { if(err){ console.error('Error-->' + err); }else{ console.log('Status-->' + result.CommonMsg.Status); if(result.CommonMsg.Status < 300 && result.InterfaceResult){ // 读取对象内容 console.log('Object Content:'); console.log(result.InterfaceResult.Content); } } });
- Android