日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

如何在微信小程序環境下將文件上傳到OSS

微信小程序可以將圖片、文檔、視頻等文件上傳到OSS,實現文件的云端存儲和分發。

方案概覽

微信小程序上傳文件到OSS的過程如下:

image

要實現微信小程序上傳文件到OSS,只需兩步:

  1. 配置服務端:在ECS,創建一個實例,用于從STS服務獲取一個臨時訪問憑證,然后使用臨時訪問憑證為微信小程序生成上傳文件到OSS所需的憑證簽名。

  2. 配置微信小程序:在小程序平臺,使用Bucket域名配置微信小程序的合法域名,確保小程序向OSS發送文件的請求不會被微信攔截;在微信小程序端,實現從ECS獲取簽名并使用簽名上傳文件到OSS的功能。

操作步驟

步驟一:配置服務端

說明

在實際部署時,如果您已經有自己的ECS服務器,則無需創建該ECS實例,可直接進行第2ECS服務端計算簽名。

  1. 創建并連接ECS實例。

    操作步驟

    創建ECS實例

    請您進入自定義購買頁面,并根據如下各模塊的內容,創建或選擇購買ECS實例所需的基礎資源。

    1. 選擇地域 & 付費類型

      1. 根據業務需求,選擇合適的付費類型。本文選擇按量付費模式,此模式操作相對靈活。

      2. 基于業務場景對時延的要求,選擇地域。通常來說離ECS實例的物理距離越近,網絡時延越低,訪問速度越快。本文以選擇華東1(杭州)為例。

        image

    1. 創建專有網絡VPC & 交換機

      創建VPC時,請您選擇和ECS相同的地域,并根據業務需求規劃網段。本文以創建華東1(杭州)地域的VPC和交換機為例。創建完畢后返回ECS購買頁,刷新并選擇VPC及交換機。

      說明

      創建VPC時,可同時創建交換機。

      image

      image

      image

    1. 選擇規格 & 鏡像

      選擇實例的規格及鏡像,鏡像為實例確定安裝的操作系統及版本。本文選擇的實例規格為ecs.e-c1m1.large,在滿足測試需求的同時,價格較為實惠。鏡像為公共鏡像Alibaba Cloud Linux 3.2104 LTS 64。

      image

    1. 選擇存儲

      ECS實例選擇系統盤,并按需選擇數據盤。本文實現簡單Web系統搭建,只需要系統盤存儲操作系統,無需數據盤。

      image

    1. 綁定公網IP

      本實例需要支持公網訪問。為了簡化操作,本文選擇直接為實例分配公網IP。您也可以在創建實例后,為實例綁定彈性公網IP,具體操作,請參見EIP綁定至ECS實例。

      說明
      • 若未綁定公網IP,將無法使用SSHRDP通過公網直接訪問實例,也無法通過公網驗證實例中Web服務的搭建。

      • 本文選擇按使用流量的帶寬計費模式。此模式只需為所消耗的公網流量付費。更多信息,請參見公網帶寬計費。

      image

    1. 創建安全組

      為實例創建安全組。安全組是一種虛擬網絡防火墻,能夠控制ECS實例的出入流量。創建時,需要設置放行以下指定端口,便于后續訪問ECS實例。

      端口范圍:SSH(22)、RDP(3389)、HTTP(80)、HTTPS(443)。

      說明
      • 端口范圍處選中的是ECS實例上運行的應用需開放的端口。

      • 此處創建的安全組默認設置0.0.0.0/0作為源的規則。0.0.0.0/0表示允許全網段設備訪問指定的端口,如果您知道請求端的IP地址,建議后續設置為具體的IP范圍。具體操作,請參見修改安全組規則。

      image

    1. 創建密鑰對

      1. 密鑰對可作為登錄時證明個人身份的安全憑證,創建完成后,必須下載私鑰,以供后續連接ECS實例時使用。創建完畢后返回ECS購買頁,刷新并選擇密鑰對。

      2. root具有操作系統的最高權限,使用root作為登錄名可能會導致安全風險,建議您選擇ecs-user作為登錄名。

        說明

        創建密鑰對后,私鑰會自動下載,請您關注瀏覽器的下載記錄,保存.pem格式的私鑰文件。

        image

    1. 創建并查看ECS實例

      創建或選擇好ECS實例所需的基礎資源后,勾選《云服務器ECS服務條款》、《云服務器ECS退訂說明》,單擊確認下單。在提示成功的對話框中,單擊管理控制臺,即可在控制臺查看到創建好的ECS實例。請您保存以下數據,以便在后續操作中使用。

      • 實例ID:便于在實例列表中查詢到該實例。

      • 地域:便于在實例列表中查詢到該實例。

      • 公網IP地址:便于在后續使用ECS實例時,做Web服務的部署結果驗證。

      imageimage

    連接ECS實例
    1. 云服務器ECS控制臺實例列表頁面,根據地域、實例ID找到創建好的ECS實例,單擊操作列下的遠程連接。image

    2. 遠程連接對話框中,單擊通過Workbench遠程連接對應的立即登錄。image

    3. 登錄實例對話框中,選擇認證方式SSH密鑰認證,用戶名為ecs-user,輸入或上傳創建密鑰對時下載的私鑰文件,單擊確定,即可登錄ECS實例。

      說明

      私鑰文件在創建密鑰對時自動下載到本地,請您關注瀏覽器的下載記錄,查找.pem格式的私鑰文件。

      image

    4. 顯示如下頁面后,即說明您已成功登錄ECS實例。image

  2. ECS服務端計算簽名。

    重要

    服務端提供了以下兩種方式獲取STS臨時訪問憑證并計算簽名。

    • ECS扮演RAM角色獲取STS臨時訪問憑證計算簽名:服務端不保留AK信息,采用ECS扮演RAM角色的方式,去訪問STS服務以獲取臨時訪問憑證并計算簽名,最大程度上降低了AK信息泄露的風險,安全性較高。

    • RAM用戶獲取STS臨時訪問憑證計算簽名:服務端需要保留AK信息,通過獲取配置于服務端環境變量里的RAM用戶AK信息,進而訪問STS服務獲取臨時訪問憑證并計算簽名,安全性較低。

    ECS扮演RAM角色獲取STS臨時訪問憑證計算簽名

    1. ECS綁定RAM角色。

      操作步驟

      1. 進入RAM訪問控制的創建角色頁面。

      2. 在創建角色頁面勾選阿里云服務,單擊下一步

        image

      3. 勾選普通服務角色,填寫角色名稱并選擇受信服務為云服務器后,單擊完成,即可完成創建。

        image

      4. 創建完畢后單擊為角色授權 > 新增授權,在權限策略中勾選ALiyunOSSFullAccess權限后單擊確認新增授權。

        說明

        倘若您對訪問控制權限較為熟悉,那么可以直接進入創建權限策略頁面,按需創建更為精準的自定義授權,隨后將其授予RAM角色,以此防止權限出現冗余情況。

        image

      5. 進入云服務器ECS實例頁面,在頁面上方選擇ECS實例所處地域,然后在實例頁面單擊目標實例右側image按鈕,單擊授予/收回RAM角色。

        image

      6. 授予/收回RAM角色彈出框選擇目標RAM角色,完成ECS綁定RAM角色。

        image

    2. 服務端計算簽名。

      Java

      請參考以下示例完成Java服務端的V4簽名計算。完整示例工程請部署upload_server.zip。

      • 配置依賴。

        <!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>credentials-java</artifactId>
            <version>0.3.4</version>
        </dependency>
        
        <dependency>
            <groupId>com.aliyun.kms</groupId>
            <artifactId>kms-transfer-client</artifactId>
            <version>0.1.0</version>
        </dependency>
        
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>
      • API接口示例。

        package com.example.demo.controller;
        
        import com.example.demo.util.ECSGenerateSignature;
        import com.example.demo.util.RAMGenerateSignature;
        import com.fasterxml.jackson.core.JsonProcessingException;
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        @RestController
        public class VxController {
        
            /**
             * 使用ECS扮演RAM角色方式獲取臨時訪問憑證,計算簽名信息,返回小程序端。
             * @return
             * @throws JsonProcessingException
             */
            @GetMapping("/generate_signature")
            public String generate_signature() throws JsonProcessingException {
                ECSGenerateSignature ecsGenerateSignature = new ECSGenerateSignature();
                return ecsGenerateSignature.getSignature();
            }
        
        }
        
      • 簽名信息工具類示例。

        package com.example.demo.util;
        
        import com.aliyun.credentials.models.CredentialModel;
        import com.aliyun.oss.common.auth.Credentials;
        import com.aliyun.oss.common.auth.CredentialsProvider;
        import com.aliyun.oss.common.auth.DefaultCredentials;
        import com.aliyun.oss.common.utils.BinaryUtil;
        import com.fasterxml.jackson.core.JsonProcessingException;
        import com.fasterxml.jackson.databind.ObjectMapper;
        import org.apache.commons.codec.binary.Base64;
        
        import javax.crypto.Mac;
        import javax.crypto.spec.SecretKeySpec;
        import java.time.Instant;
        import java.time.ZoneId;
        import java.time.ZonedDateTime;
        import java.time.format.DateTimeFormatter;
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.List;
        import java.util.Map;
        
        /**
         * ECS扮演RAM角色方式獲取STS臨時訪問憑證計算簽名
         */
        public class ECSGenerateSignature {
        
            public String getSignature() throws JsonProcessingException {
        
                com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config();
                config.setType("ecs_ram_role");   //固定值無需更改
                config.setRoleName("roleName");   //請替換為ECS扮演的角色名稱
                final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config);
                //創建一個匿名內部類實現CredentialsProvider接口,用于提供阿里云OSS操作所需的憑證信息
                CredentialsProvider credentialsProvider = new CredentialsProvider() {
                    @Override
                    public void setCredentials(Credentials credentials) {
                    }
        
                    @Override
                    public Credentials getCredentials() {
                        CredentialModel credential = credentialsClient.getCredential();
                        return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken());
                    }
        
                };
        
                String accessKeyId = credentialsProvider.getCredentials().getAccessKeyId();   //獲取AK
                String secretAccessKey = credentialsProvider.getCredentials().getSecretAccessKey();   //獲取SK
                String securityToken = credentialsProvider.getCredentials().getSecurityToken();   //獲取Token
        
                //格式化請求日期
                long now = System.currentTimeMillis() / 1000;
                ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
                ZonedDateTime dtObjPlus3h = dtObj.plusHours(3);
                //請求時間
                DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
                String dtObj1 = dtObj.format(dtObj1Formatter);
                //請求日期
                DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                String dtObj2 = dtObj.format(dtObj2Formatter);
                //請求過期時間
                DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);
        
                // 創建policy
                ObjectMapper mapper = new ObjectMapper();
        
                Map<String, Object> policy = new HashMap<>();
                policy.put("expiration", expirationTime);
        
                List<Object> conditions = new ArrayList<>();
        
                Map<String, String> bucketCondition = new HashMap<>();
                bucketCondition.put("bucket", "bucketname");    //請替換為目標Bucket名稱
                conditions.add(bucketCondition);
        
                Map<String, String> signatureVersionCondition = new HashMap<>();
                signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
                conditions.add(signatureVersionCondition);
        
                Map<String, String> credentialCondition = new HashMap<>();
                credentialCondition.put("x-oss-credential",  accessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request"); // 替換為實際的 access key id
                conditions.add(credentialCondition);
        
                Map<String, String> token = new HashMap<>();
                token.put("x-oss-security-token", securityToken);
                conditions.add(token);
        
                Map<String, String> dateCondition = new HashMap<>();
                dateCondition.put("x-oss-date", dtObj1);
                conditions.add(dateCondition);
        
                policy.put("conditions", conditions);
                String jsonPolicy = mapper.writeValueAsString(policy);
        
                //構造待簽名字符串(StringToSign)
                String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        
                //計算SigningKey
                byte[] dateKey = hmacsha256(("aliyun_v4" + secretAccessKey).getBytes(), dtObj2);
                byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");
                byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
                byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        
                //計算Signature
                byte[] result = hmacsha256(signingKey, stringToSign);
                String signature = BinaryUtil.toHex(result);
        
                Map<String, String> messageMap = new HashMap<>();
                messageMap.put("security_token", securityToken);
                messageMap.put("signature", signature);
                messageMap.put("x_oss_date", dtObj1);
                messageMap.put("x_oss_credential", accessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request");
                messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
                messageMap.put("policy", stringToSign);
                ObjectMapper objectMapper = new ObjectMapper();
                //打印返回至客戶端的簽名信息
                System.out.println(objectMapper.writeValueAsString(messageMap));
                return objectMapper.writeValueAsString(messageMap);
            }
        
        
            /**
             * 使用HMAC-SHA256算法計算給定密鑰和數據的哈希值的靜態方法
             * @param key
             * @param data
             * @return
             */
            public static byte[] hmacsha256(byte[] key,String data){
                try {
                    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
                    Mac mac = Mac.getInstance("HmacSHA256");
                    mac.init(secretKeySpec);
                    byte[] hmacBytes = mac.doFinal(data.getBytes());
                    return hmacBytes;
                }catch (Exception e){
                    throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
                }
            }
        }
        

      Python

      請參考以下示例完成Python服務端的V4簽名計算。

      • 配置依賴。

        sudo pip install oss2  
        sudo pip install alibabacloud_credentials
      • 代碼示例。

        from flask import Flask, jsonify
        import base64
        import hmac
        import hashlib
        import os
        import datetime
        import json
        import time
        from alibabacloud_credentials.client import Client as CredClient
        from alibabacloud_credentials.models import Config as CredConfig
        
        app = Flask(__name__)
        
        
        def hmacsha256(key, data):
            """
            計算HMAC-SHA256哈希值的函數
        
            :param key: 用于計算哈希的密鑰,字節類型
            :param data: 要進行哈希計算的數據,字符串類型
            :return: 計算得到的HMAC-SHA256哈希值,字節類型
            """
            try:
                mac = hmac.new(key, data.encode(), hashlib.sha256)
                hmacBytes = mac.digest()
                return hmacBytes
            except Exception as e:
                raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")
        
        
        @app.route('/generate_signature', methods=['GET'])
        def generate_signature():
            """
            處理生成簽名信息的請求,執行相關邏輯流程,包括獲取環境變量、創建策略、構造待簽名字符串、計算簽名等操作,
            并返回生成的簽名信息。
            :return: JSON格式的響應,包含簽名信息的字典,格式如下:
            {
                "policy": "policy字符串",
                "x-oss-signature-version": "OSS4-HMAC-SHA256",
                "x-oss-credential": "accesskeyid/日期/cn-hangzhou/oss/aliyun_v4_request",
                "x-oss-date": "請求時間",
                "signature": "簽名",
                "security_token": "安全令牌"
            }
            """
            credentialConfig = CredConfig(
                # 固定值無需更改
                type='ecs_ram_role',
                # 請替換為ECS扮演的角色名稱
                role_name='role_name'
            )
            credentialsClient = CredClient(credentialConfig)
            credential = credentialsClient.get_credential()
        
            # 獲取AK
            accesskeyid = credential.access_key_id
            # 獲取SK
            accesskeysecret = credential.access_key_secret
            # 獲取Token
            security_token = credential.security_token
        
            now = int(time.time())
        
            # 將時間戳轉換為datetime對象
            dt_obj = datetime.datetime.utcfromtimestamp(now)
            # 在當前時間增加3小時,設置為請求的過期時間
            dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
        
            # 請求時間
            dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
            # 請求日期
            dt_obj_2 = dt_obj.strftime('%Y%m%d')
            # 請求過期時間
            expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
        
            # 步驟1:創建policy。
            policy = {
                "expiration": expiration_time,
                "conditions": [
                    {"bucket": "bucket_name"},   #請替換為目標Bucket名稱
                    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
                    {"x-oss-credential": f"{accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},
                    {"x-oss-security-token": security_token},
                    {"x-oss-date": dt_obj_1},
                ]
            }
            policy_str = json.dumps(policy).strip()
        
            # 步驟2:構造待簽名字符串(StringToSign)
            stringToSign = base64.b64encode(policy_str.encode()).decode()
        
            # 步驟3:計算SigningKey
            dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).encode(), dt_obj_2)
            dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")
            dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
            signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
        
            # 步驟4:計算Signature
            result = hmacsha256(signingKey, stringToSign)
            signature = result.hex()
        
            return jsonify({
                "policy": stringToSign,  #表單域
                "x_oss_signature_version": "OSS4-HMAC-SHA256",  #指定簽名的版本和算法,固定值為OSS4-HMAC-SHA256
                "x_oss_credential": f"{accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request",  #指明派生密鑰的參數集
                "x_oss_date": dt_obj_1,  #請求的時間
                "signature": signature,  #簽名認證描述信息
                "security_token": security_token  #安全令牌
            })
        
        
        if __name__ == "__main__":
            app.run(host='0.0.0.0', port=5000)

    RAM用戶獲取STS臨時訪問憑證計算簽名

    說明
    • 請確保您的RAM用戶具備上傳文件至OSS以及訪問STS服務的權限,如AliyunOSSFullAccessAliyunSTSAssumeRoleAccess權限。具體操作:進入RAM用戶頁面,選中目標用戶后單擊右側添加權限,接著在權限策略處添加相應權限。

    • 若您對訪問控制權限較為熟悉,那么可以直接進入創建權限策略頁面,按需創建更為精準的自定義授權,隨后將其授予RAM用戶,以此防止權限出現冗余情況。

    Java

    請參考以下示例完成Java服務端的V4簽名計算。完整示例工程請部署upload_server.zip。

    • 配置依賴。

      <dependency>
          <groupId>com.aliyun.oss</groupId>
          <artifactId>aliyun-sdk-oss</artifactId>
          <version>3.17.4</version>
      </dependency>
    • 配置環境變量。

      說明
      • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>請分別替換為RAM用戶的AccessKey ID、AccessKeySecret。如何創建AccessKey IDAccessKeySecret請參見創建AccessKey。

      • <ROLE_ARN>請替換為目標角色ARN,在角色頁面單擊目標RAM角色名稱,然后在基本信息區域查看對應的ARN。如何創建角色請參見創建RAM角色并授權

      • macOS/Linux/Unix系統。

        export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
        export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
        export OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Windows系統。

        set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
        set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
        set OSS_STS_ROLE_ARN=<ROLE_ARN>
    • API接口示例。

      package com.example.demo.controller;
      
      import com.example.demo.util.ECSGenerateSignature;
      import com.example.demo.util.RAMGenerateSignature;
      import com.fasterxml.jackson.core.JsonProcessingException;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      public class VxController {
      
          /**
           * 使用環境變量中的AK獲取臨時訪問憑證,計算簽名信息,返回小程序端。
           * @return
           * @throws JsonProcessingException
           */
          @GetMapping("/generate_signature")
          public String generate_signature() throws JsonProcessingException {
              RAMGenerateSignature ramGenerateSignature = new RAMGenerateSignature();
              return ramGenerateSignature.getSignature();
          }
      
      }
      
    • 簽名信息工具類示例。

      package com.example.demo.util;
      
      import com.aliyun.oss.common.utils.BinaryUtil;
      import com.fasterxml.jackson.core.JsonProcessingException;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import org.apache.commons.codec.binary.Base64;
      import com.aliyuncs.DefaultAcsClient;
      import com.aliyuncs.IAcsClient;
      import com.aliyuncs.auth.sts.AssumeRoleRequest;
      import com.aliyuncs.auth.sts.AssumeRoleResponse;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.profile.DefaultProfile;
      
      import javax.crypto.Mac;
      import javax.crypto.spec.SecretKeySpec;
      import java.time.Instant;
      import java.time.ZoneId;
      import java.time.ZonedDateTime;
      import java.time.format.DateTimeFormatter;
      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      
      /**
       * 使用環境變量中的AK獲取臨時訪問憑證計算簽名
       */
      public class RAMGenerateSignature {
      
          public String getSignature() throws JsonProcessingException {
      
              //獲取發送STS請求基礎信息
              String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");    //環境變量中獲取access_key_id
              String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");    //環境變量中獲取access_key_secret
              String roleArnForOssUpload = System.getenv("OSS_STS_ROLE_ARN");    //環境變量中獲取ARN
              String regionId = "cn-hangzhou";    //發起STS請求所在的地域
              String roleSessionName = "<YOUR_ROLE_SESSION_NAME>";    //色會話名稱,用來區分不同的令牌,可自定義
              Long durationSeconds = 3600L;   //臨時訪問憑證的有效時間
      
              //初始化客戶端
              DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
              IAcsClient client = new DefaultAcsClient(profile);
      
              AssumeRoleRequest request = new AssumeRoleRequest();
              request.setRoleArn(roleArnForOssUpload);
              request.setRoleSessionName(roleSessionName);
              request.setDurationSeconds(durationSeconds);
      
              //定義STS臨時訪問憑證變量
              String STSaccessKeyId = null;
              String STSsecretAccessKey = null;
              String securityToken = null;
      
              try {
                  AssumeRoleResponse response = client.getAcsResponse(request);
      
                  //將請求返回的STS臨時訪問憑證賦值到自定義變量中
                  STSaccessKeyId = response.getCredentials().getAccessKeyId();
                  STSsecretAccessKey = response.getCredentials().getAccessKeySecret();
                  securityToken = response.getCredentials().getSecurityToken();
      
              } catch (ClientException e) {
                  e.printStackTrace();
              }
      
              //格式化請求日期
              long now = System.currentTimeMillis() / 1000;
              ZonedDateTime dtObj = ZonedDateTime.ofInstant(Instant.ofEpochSecond(now), ZoneId.of("UTC"));
              ZonedDateTime dtObjPlus3h = dtObj.plusHours(3);
              //請求時間
              DateTimeFormatter dtObj1Formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
              String dtObj1 = dtObj.format(dtObj1Formatter);
              //請求日期
              DateTimeFormatter dtObj2Formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
              String dtObj2 = dtObj.format(dtObj2Formatter);
              //請求過期時間
              DateTimeFormatter expirationTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
              String expirationTime = dtObjPlus3h.format(expirationTimeFormatter);
      
              // 創建policy
              ObjectMapper mapper = new ObjectMapper();
      
              Map<String, Object> policy = new HashMap<>();
              policy.put("expiration", expirationTime);
      
              List<Object> conditions = new ArrayList<>();
      
              Map<String, String> bucketCondition = new HashMap<>();
              bucketCondition.put("bucket", "bucketname");  //請替換為目標bucket名稱
              conditions.add(bucketCondition);
      
              Map<String, String> signatureVersionCondition = new HashMap<>();
              signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
              conditions.add(signatureVersionCondition);
      
              Map<String, String> credentialCondition = new HashMap<>();
              credentialCondition.put("x-oss-credential",  STSaccessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request"); // 替換為實際的 access key id
              conditions.add(credentialCondition);
      
              Map<String, String> token = new HashMap<>();
              token.put("x-oss-security-token", securityToken);
              conditions.add(token);
      
              Map<String, String> dateCondition = new HashMap<>();
              dateCondition.put("x-oss-date", dtObj1);
              conditions.add(dateCondition);
      
              policy.put("conditions", conditions);
              String jsonPolicy = mapper.writeValueAsString(policy);
      
              //構造待簽名字符串(StringToSign)
              String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
      
              //計算SigningKey
              byte[] dateKey = hmacsha256(("aliyun_v4" + STSsecretAccessKey).getBytes(), dtObj2);
              byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");
              byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
              byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
      
              //計算Signature
              byte[] result = hmacsha256(signingKey, stringToSign);
              String signature = BinaryUtil.toHex(result);
      
              Map<String, String> messageMap = new HashMap<>();
              messageMap.put("security_token", securityToken);
              messageMap.put("signature", signature);
              messageMap.put("x_oss_date", dtObj1);
              messageMap.put("x_oss_credential", STSaccessKeyId + "/" + dtObj2 + "/cn-hangzhou/oss/aliyun_v4_request");
              messageMap.put("x_oss_signature_version", "OSS4-HMAC-SHA256");
              messageMap.put("policy", stringToSign);
              ObjectMapper objectMapper = new ObjectMapper();
              //打印返回至客戶端的簽名信息
      //        System.out.println(objectMapper.writeValueAsString(messageMap));
              return objectMapper.writeValueAsString(messageMap);
          }
      
          /**
           * 使用HMAC-SHA256算法計算給定密鑰和數據的哈希值的靜態方法
           * @param key
           * @param data
           * @return
           */
          public static byte[] hmacsha256(byte[] key,String data){
              try {
                  SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
                  Mac mac = Mac.getInstance("HmacSHA256");
                  mac.init(secretKeySpec);
                  byte[] hmacBytes = mac.doFinal(data.getBytes());
                  return hmacBytes;
              }catch (Exception e){
                  throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
              }
          }
      }
      

    Python

    請參考以下示例完成Python服務端的V4簽名計算。

    • 配置依賴。

      pip install oss2  
      pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials
    • 配置環境變量。

      說明
      • <ALIBABA_CLOUD_ACCESS_KEY_ID><ALIBABA_CLOUD_ACCESS_KEY_SECRET>請分別替換為RAM用戶的AccessKey ID、AccessKeySecret。如何創建AccessKey IDAccessKeySecret請參見創建AccessKey。

      • <ROLE_ARN>請替換為目標角色ARN,在角色頁面單擊目標RAM角色名稱,然后在基本信息區域查看對應的ARN。如何創建角色請參見創建RAM角色并授權。

      • macOS/Linux/Unix

        export OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
        export OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
        export OSS_STS_ROLE_ARN=<ROLE_ARN>
      • Windows

        set OSS_ACCESS_KEY_ID=<ALIBABA_CLOUD_ACCESS_KEY_ID>
        set OSS_ACCESS_KEY_SECRET=<ALIBABA_CLOUD_ACCESS_KEY_SECRET>
        set OSS_STS_ROLE_ARN=<ROLE_ARN>
    • 代碼示例。

      from flask import Flask, jsonify
      import base64
      import hmac
      import hashlib
      import os
      import datetime
      import json
      import time
      from alibabacloud_tea_openapi.models import Config
      from alibabacloud_sts20150401.client import Client as Sts20150401Client
      from alibabacloud_sts20150401 import models as sts_20150401_models
      from alibabacloud_credentials.client import Client as CredentialClient
      import os
      
      app = Flask(__name__)
      
      def hmacsha256(key, data):
          """
          計算HMAC-SHA256哈希值的函數
      
          :param key: 用于計算哈希的密鑰,字節類型
          :param data: 要進行哈希計算的數據,字符串類型
          :return: 計算得到的HMAC-SHA256哈希值,字節類型
          """
          try:
              mac = hmac.new(key, data.encode(), hashlib.sha256)
              hmacBytes = mac.digest()
              return hmacBytes
          except Exception as e:
              raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")
      
      
      @app.route('/generate_signature', methods=['GET'])
      def generate_signature():
          """
          處理生成簽名信息的請求,執行相關邏輯流程,包括獲取環境變量、創建策略、構造待簽名字符串、計算簽名等操作,
          并返回生成的簽名信息。
          :return: JSON格式的響應,包含簽名信息的字典,格式如下:
          {
              "policy": "policy字符串",
              "x-oss-signature-version": "OSS4-HMAC-SHA256",
              "x-oss-credential": "accesskeyid/日期/cn-hangzhou/oss/aliyun_v4_request",
              "x-oss-date": "請求時間",
              "signature": "簽名",
              "security_token": "安全令牌"
          }
          """
          access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
          access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
          role_arn_for_oss_upload = os.environ.get('OSS_STS_ROLE_ARN')
      
          # 自定義會話名稱
          role_session_name = 'role_session_name'  
      
          # 指定過期時間,單位為秒
          expire_time = 3600  
      
          bucket = 'examplebucket'
          region_id = 'cn-hangzhou'
      
          # 初始化配置,直接傳遞憑據
          config = Config(
              region_id=region_id,
              access_key_id=access_key_id,
              access_key_secret=access_key_secret
          )
      
          # 創建 STS 客戶端并獲取臨時憑證
          sts_client = Sts20150401Client(config=config)
          assume_role_request = sts_20150401_models.AssumeRoleRequest(
              role_arn=role_arn_for_oss_upload,
              role_session_name=role_session_name
          )
          response = sts_client.assume_role(assume_role_request)
          token_data = response.body.credentials.to_map()
      
          # 使用 STS 返回的臨時憑據
          sts_accesskeyid = token_data['AccessKeyId']
          sts_accesskeysecret = token_data['AccessKeySecret']
          security_token = token_data['SecurityToken']
      
          now = int(time.time())
      
          # 將時間戳轉換為datetime對象
          dt_obj = datetime.datetime.utcfromtimestamp(now)
          # 在當前時間增加3小時,設置為請求的過期時間
          dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)
      
          # 請求時間
          dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
          # 請求日期
          dt_obj_2 = dt_obj.strftime('%Y%m%d')
          # 請求過期時間
          expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
      
          # 步驟1:創建policy。
          policy = {
              "expiration": expiration_time,
              "conditions": [
                  {"bucket": "cjl3"},   #請替換為目標Bucket名稱
                  {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
                  {"x-oss-credential": f"{sts_accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},
                  {"x-oss-security-token": security_token},
                  {"x-oss-date": dt_obj_1},
              ]
          }
          policy_str = json.dumps(policy).strip()
      
          # 步驟2:構造待簽名字符串(StringToSign)
          stringToSign = base64.b64encode(policy_str.encode()).decode()
      
          # 步驟3:計算SigningKey
          dateKey = hmacsha256(("aliyun_v4" + sts_accesskeysecret).encode(), dt_obj_2)
          dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")
          dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
          signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
      
          # 步驟4:計算Signature
          result = hmacsha256(signingKey, stringToSign)
          signature = result.hex()
      
          return jsonify({
              "policy": stringToSign,
              "x_oss_signature_version": "OSS4-HMAC-SHA256",
              "x_oss_credential": f"{sts_accesskeyid}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request",
              "x_oss_date": dt_obj_1,
              "signature": signature,
              "security_token": security_token
          })
      
      
      if __name__ == "__main__":
          app.run(host='0.0.0.0', port=5000)

步驟二:配置微信小程序

  1. 為了確保小程序向OSS發送文件的請求不會被微信攔截,在小程序平臺,使用Bucket域名配置微信小程序的合法域名。

    1. 進入Bucket列表,選擇目標Bucket后在Bucket內的左側導航欄,單擊概覽,然后在訪問端口區域復制Bucket名。

      image

    2. 登錄微信公眾平臺,將上傳和下載的合法域名填寫為Bucket的外網訪問域名。如圖所示。

      說明

      實際業務中,建議您將OSS提供的外網域名和您自己的域名進行綁定,以便使用自定義域名訪問OSS存儲空間中的文件。配置步驟,請參見綁定自定義域名。

      image

  2. 在微信小程序端,使用從ECS服務端獲取到的V4簽名憑證信息,發送請求上傳文件到OSS。

    說明

    關于上傳參數詳細說明,請參見簽名版本4表單元素。

    小程序端上傳文件index.js文件示例代碼如下,完整示例工程請部署uploadoss .zip

    Page({
      data: {
        key: 'filename.txt',  //上傳文件名稱
        policy: '',
        xOssSecurityToken: '',
        xOssSignatureVersion: '',
        xOssCredential: '',
        xOssDate: '',
        xOssSignature: ''
      },
    
      //上傳文件方法 
      uploadFileToOSS(filePath, callback) {
        const {
          key,
          policy,
          xOssSecurityToken,
          xOssSignatureVersion,
          xOssCredential,
          xOssDate,
          xOssSignature
        } = this.data;
       
        const apiUrl='http://<ECS實例公網IP地址>:5000/generate_signature'   //請將ip地址和端口替換為實際服務器公網ip地址及端口
        // 發送請求獲取簽名信息 
        wx.request({
          url: apiUrl,
          success: (res) => {
          
            this.data.xOssSignatureVersion = res.data.x_oss_signature_version;
            this.data.xOssCredential = res.data.x_oss_credential;
            this.data.xOssDate = res.data.x_oss_date;
            this.data.xOssSignature = res.data.signature;
            this.data.xOssSecurityToken = res.data.security_token;
            this.data.policy = res.data.policy;
            
            //上傳參數 
            const formData = {
              key,  //上傳文件名稱
              policy: this.data.policy,   //表單域
              'x-oss-signature-version': this.data.xOssSignatureVersion,    //指定簽名的版本和算法
              'x-oss-credential': this.data.xOssCredential,   //指明派生密鑰的參數集
              'x-oss-date': this.data.xOssDate,   //請求的時間
              'x-oss-signature': this.data.xOssSignature,   //簽名認證描述信息
              'x-oss-security-token': this.data.xOssSecurityToken,    //安全令牌
              success_action_status: "200"    //上傳成功后響應狀態碼
            };
    
            // 發送請求上傳文件 
            wx.uploadFile({
              url: 'https://*********.aliyuncs.com',  // Bucket域名 請替換為目標Bucket域名
              filePath: filePath,
              name: 'file',   //固定值為file
              formData: formData,
              success(res) {
                console.log('上傳響應:', res);
                if (res.statusCode === 200) {
                  callback(null, res.data); // 上傳成功
                } else {
                  console.error('上傳失敗,狀態碼:', res.statusCode);
                  console.error('失敗響應:', res);
                  callback(res); // 上傳失敗,返回響應
                }
              },
              fail(err) {
                console.error('上傳失敗:', err); // 輸出錯誤信息
                wx.showToast({ title: '上傳失敗,請重試!', icon: 'none' });
                callback(err); // 調用回調處理錯誤
              }
            });
          },
          fail: (err) => {
            console.error('請求接口失敗:', err);
            wx.showToast({ title: '獲取上傳參數失敗,請重試!', icon: 'none' });
          }
        });
      },
    
      //點擊上傳文件按鈕觸發上傳文件代碼邏輯  
      chooseAndUploadFile() {
        wx.chooseMessageFile({
          count: 1, // 選擇一個文件
          type: 'all', // 支持所有類型的文件
          success: (res) => {
            console.log('選擇的文件:', res.tempFiles); // 輸出選擇的文件信息
            if (res.tempFiles.length > 0) {
              const tempFilePath = res.tempFiles[0].path; // 獲取選擇的文件路徑
              console.log('選擇的文件路徑:', tempFilePath); // 輸出文件路徑
              this.uploadFileToOSS(tempFilePath, (error, data) => {
                if (error) {
                  wx.showToast({ title: '上傳失敗!', icon: 'none' });
                  console.error('上傳失敗:', error); // 輸出具體的錯誤信息
                } else {
                  wx.showToast({ title: '上傳成功!', icon: 'success' });
                  console.log('上傳成功:', data); // 輸出上傳成功后的數據
                }
              });
            } else {
              wx.showToast({ title: '未選擇文件!', icon: 'none' });
            }
          },
          fail: (err) => {
            wx.showToast({ title: '選擇文件失敗!', icon: 'none' });
            console.error('選擇文件失敗:', err); // 輸出選擇文件的錯誤信息
          }
        });
      }
    });

結果驗證

  1. 編譯運行后,在微信小程序界面單擊上傳文件

    微信小程序上傳文件到OSS.gif

  2. Bucket列表頁面,選擇上傳文件的Bucket并打開,單擊右上角任務列表 > 上傳列表 您可以在上傳列表中看到您通過小程序上傳的文件。

    image