
# 使用临时安全凭证直传OBS并设置上传回调
#### 应用场景
OBS支持使用临时安全凭证（临时AK/SK和securitytoken）进行授权访问，同时支持为临时安全凭证配置权限策略来指定使用该临时安全凭证时允许执行的操作。临时安全凭证的含义请参见[什么是临时安全凭证？](https://support.huaweicloud.com/perms-cfg-obs/obs_40_0008.html#section1)
移动应用客户端可以使用指定了权限策略的临时安全凭证来访问OBS，实现数据直传并设置上传回调，如[图1]所示。整个过程不会暴露用户的永久AK/SK，降低账号泄露带来的安全风险。
#### 方案架构
图1使用临时安全凭证直传OBS并设置上传回调流程   
![](https://support.huaweicloud.com/bestpractice-obs/zh-cn_image_0000002393877317.png "点击放大")
**角色分析如下：**
- 应用客户端：即最终用户手机上的APP，负责向应用服务器发出申请临时安全凭证的请求，以及访问OBS完成数据上传或下载。
- 应用服务器：即提供该Android/iOS应用的开发者开发的APP后台服务，用于用户管理和授权管理，接收回调请求等。
- 对象存储服务：即华为云对象存储服务，负责处理移动应用的数据请求。
- 统一身份认证服务：即华为云统一身份认证服务，负责生成临时安全凭证。
**实现流程如下：**
1. 应用客户端向应用服务器申请一个临时操作凭证。
2. 应用服务器向统一身份认证服务请求一个临时安全凭证。
3. 统一身份认证服务向应用服务器返回一个临时安全凭证。
4. 应用服务器将临时安全凭证发放给应用客户端。
5. 应用客户端使用安全凭证完成OBS数据上传并设置回调参数。
6. OBS上传完成后回调客户的回调Server。
7. OBS返回给应用客户端结果。
 
#### 前提条件
已创建桶，并将桶权限设置为私有读写或者公共读私有写。
详细操作步骤请参见[创建桶](https://support.huaweicloud.com/usermanual-obs/zh-cn_topic_0045829088.html)和[配置桶策略](https://support.huaweicloud.com/usermanual-obs/obs_03_0123.html)。
#### 资源规划
最佳实践中涉及的资源如下：
表1资源说明 
| 资源                | 资源说明                                                |
|:---|:---|
| 应用客户端（APP Client） | 最终用户手机上的APP，负责向应用服务器发出申请临时安全凭证的请求，以及访问OBS完成数据上传或下载。 |
| 应用服务器（APP Server） | 提供该Android/iOS应用的开发者开发的APP后台服务，用于用户管理和授权管理，接收回调请求等。 |
| 对象存储服务（OBS）       | 华为云对象存储服务，负责处理移动应用的数据请求。                            |
| 统一身份认证服务（IAM）     | 华为云统一身份认证服务，负责生成临时安全凭证。                             |
   
#### 实施步骤
1. 获取OBS SDK开发包和IAM SDK开发包。 
   OBS SDK请在[SDK开发指南](https://support.huaweicloud.com/sdkreference-obs/obs_02_0001.html)中获取。
   IAM SDK开发包请在[IAM开发工具包](https://sdkcenter.developer.huaweicloud.com?IAM)获取。
   
   
2. 模拟应用服务器向IAM请求临时安全凭证和返回安全凭证。 
   过程如下：
   1. 获取用户的IAM用户Token。 API请参见[获取IAM用户Token（使用密码）](https://support.huaweicloud.com/api-iam/iam_30_0001.html)，SDK请参见[SDK中心](https://sdkcenter.developer.huaweicloud.com/)。
      
   
   2. 使用Token获取临时安全凭证（临时AK/SK和securitytoken），获取时需要通过Policy字段指定该安全凭证允许执行的操作权限。 API请参见[通过token获取临时访问密钥和securitytoken](https://support.huaweicloud.com/api-iam/iam_04_0002.html)，SDK请参见[SDK中心](https://sdkcenter.developer.huaweicloud.com/)。
      
   
   
   示例：获取一个有效期为900秒的临时安全凭证，该凭证只允许上传数据到桶hi-company的APPClient/APP-1/目录下。
   ```
   {
       "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"
               ]
           }
       }
   }
   ```
   
   
3. 初始化应用客户端中OBS client。 
   初始化示例：
   - Android
     ```
     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();
     ```
     ![](https://support.huaweicloud.com/bestpractice-obs/public_sys-resources/note_3.0-zh-cn.png)
     - endPoint即终端节点，可通过[地区和终端节点](https://developer.huaweicloud.com/endpoint?OBS)查询。
     
     - ak和sk即临时AK/SK，token即securitytoken，获取方式请参见[访问密钥（AK/SK）](https://support.huaweicloud.com/productdesc-obs/obs_03_0208.html)。
       
   
   - iOS
     ```
     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 *credentialProvider = [[OBSStaticCredentialProvider alloc] initWithAccessKey:AK secretKey:SK];
     securityTokencredentialProvider.securityToken = @"*** Provide your Security Token ***";
     // 初始化服务配置
     OBSServiceConfiguration *conf = [[OBSServiceConfiguration alloc] initWithURLString:endPoint credentialProvider:credentialProvider];
     // 初始化
     clientOBSClient *client  = [[OBSClient alloc] initWithConfiguration:conf];
     ```
     ![](https://support.huaweicloud.com/bestpractice-obs/public_sys-resources/note_3.0-zh-cn.png)
     - endPoint即终端节点，可通过[地区和终端节点](https://developer.huaweicloud.com/endpoint?OBS)查询。
     
     - ak和sk即临时AK/SK，token即securitytoken，获取方式请参见[访问密钥（AK/SK）](https://support.huaweicloud.com/productdesc-obs/obs_03_0208.html)。
       
   
   - web js
     ```
     // 未引入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
     });
     ```
     ![](https://support.huaweicloud.com/bestpractice-obs/public_sys-resources/note_3.0-zh-cn.png)
     - endPoint即终端节点，可通过[地区和终端节点](https://developer.huaweicloud.com/endpoint?OBS)查询。
     
     - ak和sk即临时AK/SK，token即securitytoken，获取方式请参见[访问密钥（AK/SK）](https://support.huaweicloud.com/productdesc-obs/obs_03_0208.html)。
       
   
   
   
   
4. 使用临时安全凭证完成OBS数据上传并设置上传回调，示例如下。回调的详细参数设置请参考API说明[回调](https://support.huaweicloud.com/api-obs/obs_04_0095.html)。
   
   - Android
     ```
     // obsClient 是步骤3创建的ObsClient实例
     // 流式上传并设置callback，下面示例中对象上传到OBS后，会向http://www.example.com/callback地址发送POST回调请求
     String content = "Hello OBS"; 
     obsClient.putObject("bucketname", "objectname", new ByteArrayInputStream(content.getBytes()));
     Callback callback = new Callback();
     callback.setCallbackBody("{\"bucket\":\"$(bucket)\",\"key\":\"$(key)\",\"override\":\"$(override)\"}");
     callback.setCallbackBodyType("application/json");
     callback.setCallbackUrl("http://www.example.com/callback");
     PutObjectRequest putReq = new PutObjectRequest();
     putReq.setCallback(callback);
     putReq.setBucketName("BucketName");
     putReq.setObjectKey("ObjectName");
     putReq.setInput(new ByteArrayInputStream("Hello OBS".getBytes()));
     obsClient.putObject(putReq);
     ```
     
   
   - iOS
     ```
     // obsClient 是步骤3创建的ObsClient实例
     NSString* exampleCallbackUrl = @"http://www.example.com/callback";
     NSString* exampleCallbackBody = @"bucket=$(bucket)&key=$(key)&override=$(override)";
     NSString* exampleCallbackBodyType = @"application/json";
     // 流式上传
     OBSPutObjectWithDataRequest *putObjectRequest = [[OBSPutObjectWithDataRequest alloc]initWithBucketName:@"bucketname" objectKey:@"objectname" uploadData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];     
     putObjectRequest.callback = [[OBSCallback alloc] initWithUrl:exampleCallbackUrl
                                                         withBody:exampleCallbackBody
                                                         withBodyType:exampleCallbackBodyType
                                                         withHost:exampleCallbackHost];
     // 初始化上传对象异步任务
     OBSBFTask* putObjectTask = [client putObject:putObjectRequest completionHandler:^(OBSPutObjectResponse *response, NSError *error) {
         if(error){
             // 上传失败
             NSLog(@"PutObject failed:%@", error);
         }
         if(response){
             NSLog(@"PutObject response:%@", response);
             NSString* callbackResponseString = [[NSString alloc] initWithData:response.responseRawData
                                                                      encoding:NSUTF8StringEncoding];
             NSLog(@"PutObject callbackResponseString:%@", callbackResponseString);
         }
     }];
     // 等待上传对象异步任务完成
     [putObjectTask waitUntilFinished];
     ```
     
   
   - web js
     ```
     // obsClient 是步骤3创建的ObsClient实例
     // 文本上传并设置上传回调参数
     obsClient.putObject({
             //使用Body参数指定待上传的字符串
             Bucket: 'bucketname',
             Key: 'objectname',
             Body: 'Hello OBS',
             CallbackUrl: 'http://www.example.com/callback',
             CallbackBody: 'bucket=$(bucket)&key=$(key)&override=$(override)',
             CallbackBodyType: 'application/json'
     }, function (err, result) {
             if(err){
                    console.error('Error-->' + err);
             }else{
                    console.log('Status-->' + result.CommonMsg.Status);
             }
     });
     ```
     
   
   
   
   
 
