C授权访问

本文介绍如何使用STS以及签名URL临时授权访问OSS资源。

重要

由于STS临时账号以及签名URL均需设置有效时长,当您使用STS临时账号生成签名URL执行相关操作(例如上传、下载文件)时,以最小的有效时长为准。例如您的STS临时账号的有效时长设置为1200秒、签名URL设置为3600秒时,当有效时长超过1200秒后,您无法使用此STS临时账号生成的签名URL上传文件。

注意事项

  • 本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见访问域名和数据中心

  • 本文以OSS域名新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见初始化

使用STS临时授权

OSS可以通过阿里云STS(Security Token Service)进行临时授权访问。阿里云STS是为云计算用户提供临时访问令牌的Web服务。通过STS,您可以为第三方应用或子用户(即用户身份由您自己管理的用户)颁发一个自定义时效和权限的访问凭证。关于STS的更多信息,请参见STS介绍

STS的优势如下:

  • 您无需透露您的长期密钥(AccessKey)给第三方应用,只需生成一个访问令牌并将令牌交给第三方应用。您可以自定义这个令牌的访问权限及有效期限。

  • 您无需关心权限撤销问题,访问令牌过期后自动失效。

通过STS临时授权访问OSS的步骤如下:

  1. 获取临时访问凭证

    临时访问凭证包括临时访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)。临时访问凭证有效时间单位为秒,最小值为900,最大值以当前角色设定的最大会话时间为准。更多信息,请参见设置RAM角色最大会话时间

    您可以通过以下两种方式获取临时访问凭证。

    • 方式一

      通过调用STS服务的AssumeRole接口获取临时访问凭证。

    • 方式二

      通过各语言STS SDK获取临时访问凭证。

  2. 使用STS凭证构造签名请求。

    • 上传文件

      #include "oss_api.h"
      #include "aos_http_io.h"
      /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
      const char *endpoint = "yourEndpoint";
      /* 运行本代码示例之前,请确保已使用STS服务获取的临时访问密钥设置环境变量YOUR_ACCESS_KEY_ID和YOUR_ACCESS_KEY_SECRET。*/  
      const char *access_key_id = getenv("OSS_ACCESS_KEY_ID");
      const char *access_key_secret = getenv("OSS_ACCESS_KEY_SECRET");
      /* 从STS服务获取的安全令牌(SecurityToken)。*/
      const char *sts_token = "yourStsToken";
      /* 填写Bucket名称,例如examplebucket。*/
      const char *bucket_name = "examplebucket";
      /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
      const char *object_name = "exampledir/exampleobject.txt";
      const char *object_content = "More than just cloud.";
      
      void init_options(oss_request_options_t *options)
      {
          options->config = oss_config_create(options->pool);
          /* 用char*类型的字符串初始化aos_string_t类型。*/
          aos_str_set(&options->config->endpoint, endpoint);
          aos_str_set(&options->config->access_key_id, access_key_id);
          aos_str_set(&options->config->access_key_secret, access_key_secret);
          aos_str_set(&options->config->sts_token, sts_token);
          /* 是否使用CNAME访问OSS服务。0表示不使用。*/
          options->config->is_cname = 0;
          /* 设置网络相关参数,例如超时时间等。*/
          options->ctl = aos_http_controller_create(options->pool, 0);
      }
      
      int main(int argc, char *argv[])
      {
          /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
          if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
              exit(1);
          }
      
          /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
          aos_pool_t *pool;
          /* 重新创建一个内存池,第二个参数是NULL,表示没有继承其他内存池。*/
          aos_pool_create(&pool, NULL);
          /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
          oss_request_options_t *oss_client_options;
          /* 在内存池中分配内存给options。*/
          oss_client_options = oss_request_options_create(pool);
          /* 初始化Client的选项oss_client_options。*/
          init_options(oss_client_options);
      
          /* 初始化参数。*/
          aos_string_t bucket;
          aos_string_t object;
          aos_list_t buffer;
          aos_buf_t *content = NULL;
          aos_table_t *headers = NULL;
          aos_table_t *resp_headers = NULL; 
          aos_status_t *resp_status = NULL; 
          /* 将类型为char*的数据赋值给bucket。*/
          aos_str_set(&bucket, bucket_name);
          aos_str_set(&object, object_name);
      
          aos_list_init(&buffer);
          content = aos_buf_pack(oss_client_options->pool, object_content, strlen(object_content));
          aos_list_add_tail(&content->node, &buffer);
      
          /* 上传文件。*/
          resp_status = oss_put_object_from_buffer(oss_client_options, &bucket, &object, &buffer, headers, &resp_headers);
          /* 判断文件是否上传成功。*/
          if (aos_status_is_ok(resp_status)) {
              printf("put object from buffer succeeded\n");
          } else {
              printf("put object from buffer failed\n");      
          }    
      
          /* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
          aos_pool_destroy(pool);
      
          /* 释放之前分配的全局资源。*/
          aos_http_io_deinitialize();
      
          return 0;
      }            
    • 下载文件

      #include "oss_api.h"
      #include "aos_http_io.h"
      /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
      const char *endpoint = "yourEndpoint";
      /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/  
      const char *access_key_id = getenv("OSS_ACCESS_KEY_ID");
      const char *access_key_secret = getenv("OSS_ACCESS_KEY_SECRET");
      /* 从STS服务获取的安全令牌(SecurityToken)。*/
      const char *sts_token = "yourStsToken";
      /* 填写Bucket名称,例如examplebucket。*/
      const char *bucket_name = "examplebucket";
      /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
      const char *object_name = "exampledir/exampleobject.txt";
      void init_options(oss_request_options_t *options)
      {
          options->config = oss_config_create(options->pool);
          /* 用char*类型的字符串初始化aos_string_t类型。*/
          aos_str_set(&options->config->endpoint, endpoint);
          aos_str_set(&options->config->access_key_id, access_key_id);
          aos_str_set(&options->config->access_key_secret, access_key_secret);
          aos_str_set(&options->config->sts_token, sts_token);
          /* 是否使用了CNAME。0表示不使用。*/
          options->config->is_cname = 0;
          /* 用于设置网络相关参数,比如超时时间等。*/
          options->ctl = aos_http_controller_create(options->pool, 0);
      }
      int main(int argc, char *argv[])
      {
          /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
          if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
              exit(1);
          }
          /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
          aos_pool_t *pool;
          /* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
          aos_pool_create(&pool, NULL);
          /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
          oss_request_options_t *oss_client_options;
          /* 在内存池中分配内存给options。*/
          oss_client_options = oss_request_options_create(pool);
          /* 初始化Client的选项oss_client_options。*/
          init_options(oss_client_options);
          /* 初始化参数。*/
          aos_string_t bucket;
          aos_string_t object;
          aos_list_t buffer;
          aos_buf_t *content = NULL;
          aos_table_t *params = NULL;
          aos_table_t *headers = NULL;
          aos_table_t *resp_headers = NULL; 
          aos_status_t *resp_status = NULL; 
          char *buf = NULL;
          int64_t len = 0;
          int64_t size = 0;
          int64_t pos = 0;
          aos_str_set(&bucket, bucket_name);
          aos_str_set(&object, object_name);
          aos_list_init(&buffer);
          /* 下载文件到本地内存。*/
          resp_status = oss_get_object_to_buffer(oss_client_options, &bucket, &object, 
                                       headers, params, &buffer, &resp_headers);
          if (aos_status_is_ok(resp_status)) {
              printf("get object to buffer succeeded\n");
              /* 将下载内容拷贝到buffer中。*/
              len = aos_buf_list_len(&buffer);
              buf = aos_pcalloc(pool, len + 1);
              buf[len] = '\0';
              aos_list_for_each_entry(aos_buf_t, content, &buffer, node) {
              size = aos_buf_size(content);
                  memcpy(buf + pos, content->pos, size);
                  pos += size;
              }
          }
          else {
              printf("get object to buffer failed\n");  
          }
          /* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
          aos_pool_destroy(pool);
          /* 释放之前分配的全局资源。*/
          aos_http_io_deinitialize();
          return 0;
      }

使用签名URL临时授权

注意事项

  • 生成签名URL过程中,SDK利用本地存储的密钥信息,根据特定算法计算出签名(signature),然后将其附加到URL上,以确保URL的有效性和安全性。这一系列计算和构造URL的操作都是在客户端完成,不涉及网络请求到服务端。因此,生成签名URL时不需要授予调用者特定权限。但是,为避免第三方用户无法对签名URL授权的资源执行相关操作,需要确保调用生成签名URL接口的身份主体被授予对应的权限。

    例如,通过签名URL上传文件时,需要授予oss:PutObject权限。通过签名URL下载或预览文件时,需要授予oss:GetObject权限。

  • 您可以将生成的签名URL提供给访客进行临时访问。生成签名URL时,您可以自定义URL的过期时间来限制访客的访问时长。

  • 如果需要生成HTTPS协议的签名URL,请将Endpoint中的通信协议设置为HTTPS。

  • 通过以下示例生成的签名URL中如果包含特殊符号+,可能出现无法正常访问该签名URL的现象。如需正常访问该签名URL,请将签名URL中的+替换为%2B

生成签名URL并通过签名URL上传文件

  1. 生成用于上传的签名URL

    #include "oss_api.h"
    #include "aos_http_io.h"
    /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    const char *endpoint = "yourEndpoint";
    
    /* 填写Bucket名称,例如examplebucket。*/
    const char *bucket_name = "examplebucket";
    /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
    const char *object_name = "exampledir/exampleobject.txt";
    /* 填写本地文件的完整路径。*/
    const char *local_filename = "yourLocalFilename";
    void init_options(oss_request_options_t *options)
    {
        options->config = oss_config_create(options->pool);
        /* 用char*类型的字符串初始化aos_string_t类型。*/
        aos_str_set(&options->config->endpoint, endpoint);
        /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
        aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
        aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
        /* 是否使用CNAME访问OSS服务。0表示不使用。*/
        options->config->is_cname = 0;
        /* 设置网络相关参数,例如超时时间等。*/
        options->ctl = aos_http_controller_create(options->pool, 0);
    }
    int main(int argc, char *argv[])
    {
        /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
        if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
            exit(1);
        }
        /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
        aos_pool_t *pool;
        /* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
        aos_pool_create(&pool, NULL);
        /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
        oss_request_options_t *oss_client_options;
        /* 在内存池中分配内存给options。*/
        oss_client_options = oss_request_options_create(pool);
        /* 初始化Client的选项oss_client_options。*/
        init_options(oss_client_options);
        /* 初始化参数。*/
        aos_string_t bucket;
        aos_string_t object;
        aos_string_t file;    
        aos_http_request_t *req;
        apr_time_t now;
        char *url_str;
        aos_string_t url;
        int64_t expire_time; 
        int one_hour = 3600;
        aos_str_set(&bucket, bucket_name);
        aos_str_set(&object, object_name);
        aos_str_set(&file, local_filename);
        expire_time = now / 1000000 + one_hour;    
        req = aos_http_request_create(pool);
        req->method = HTTP_PUT;
        now = apr_time_now(); 
        /* 单位:微秒 */
        expire_time = now / 1000000 + one_hour;
        /* 生成签名URL。*/
        url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req);
        aos_str_set(&url, url_str);
        printf("临时上传URL: %s\n", url_str);    
        /* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
        aos_pool_destroy(pool);
        /* 释放之前分配的全局资源。*/
        aos_http_io_deinitialize();
        return 0;
    }
  2. 通过签名URL上传文件

    您可以参考移动端Android SDK通过签名URL上传文件。更多信息,请参见通过签名URL上传文件

生成签名URL并通过签名URL下载文件

  1. 生成用于下载的签名URL

    #include "oss_api.h"
    #include "aos_http_io.h"
    /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    const char *endpoint = "yourEndpoint";
    /* 填写Bucket名称,例如examplebucket。*/
    const char *bucket_name = "examplebucket";
    /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
    const char *object_name = "exampledir/exampleobject.txt";
    /* 填写本地文件的完整路径。*/
    const char *local_filename = "yourLocalFilename";
    
    void init_options(oss_request_options_t *options)
    {
        options->config = oss_config_create(options->pool);
        /* 用char*类型的字符串初始化aos_string_t类型。*/
        aos_str_set(&options->config->endpoint, endpoint);
        /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
        aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
        aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
        /* 是否使用CNAME访问OSS服务。0表示不使用。*/
        options->config->is_cname = 0;
        /* 设置网络相关参数,例如超时时间等。*/
        options->ctl = aos_http_controller_create(options->pool, 0);
    }
    int main(int argc, char *argv[])
    {
        /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
        if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
            exit(1);
        }
        /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
        aos_pool_t *pool;
        /* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
        aos_pool_create(&pool, NULL);
        /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
        oss_request_options_t *oss_client_options;
        /* 在内存池中分配内存给options。*/
        oss_client_options = oss_request_options_create(pool);
        /* 初始化Client的选项oss_client_options。*/
        init_options(oss_client_options);
        /* 初始化参数。*/
        aos_string_t bucket;
        aos_string_t object;
        aos_string_t file;    
        aos_http_request_t *req;
        apr_time_t now;
        char *url_str;
        aos_string_t url;
        int64_t expire_time; 
        int one_hour = 3600;
        aos_str_set(&bucket, bucket_name);
        aos_str_set(&object, object_name);
        aos_str_set(&file, local_filename);
        expire_time = now / 1000000 + one_hour;    
        req = aos_http_request_create(pool);
        req->method = HTTP_GET;
        now = apr_time_now();  
        /* 单位:微秒 */
        expire_time = now / 1000000 + one_hour;
        /* 生成签名URL。*/
        url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req);
        aos_str_set(&url, url_str);
        printf("临时下载URL: %s\n", url_str);     
        /* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
        aos_pool_destroy(pool);
        /* 释放之前分配的全局资源。*/
        aos_http_io_deinitialize();
        return 0;
    }
  2. 通过签名URL下载文件

    您可以参考移动端Android SDK通过签名URL下载文件。更多信息,请参见通过签名URL下载文件