阿里雲OSS文件上傳前端搭配之后端的活


原文:https://blog.vchar.top/java/1622894400.html

雖然不用后端額外的處理,前端也可以根據阿里雲的提供的方法直接操作OSS對象存儲來上傳文件。但是由於前端的js文件是直接暴露給用戶的,即使現如今前端的什么js混淆加密等待處理方式,但是其最終都會被用戶給看到,只是查找的成本高了一點而已。因此直接使用accessKeyId和accessKeySecret是非常不安全的,因此阿里雲的對象存儲OSS根據上傳需求提供如下2種方式來進行文件的上傳。本文 參考文檔

服務端簽名后直傳

服務端簽名后直傳:這種方式適用於普通的單文件上傳,其流程是前端請求后端獲取一個token(有時效性),之后通過這個token來給阿里雲鑒權,然后上傳文件;這樣將不會直接將accessKeyId和accessKeySecret直接暴露給用戶了。其流程圖如下:

官方文檔地址: Web端PostObject直傳實踐

Java生成簽名的實現

public void generateToken(){
    // 授權訪問oss的ack
    String accessId = "<yourAccessKeyId>";
    String accessKey = "<yourAccessKeySecret>";
    // 所屬地域
    String endpoint = "oss-cn-chengdu.aliyuncs.com";
    // bucket的名稱
    String bucket = "bucket-name";
    // 格式為https://bucketname.endpoint,例如https://bucket-name.oss-cn-chengdu.aliyuncs.com
    String host = "https://" + bucket + "." + endpoint;
    // 要上傳的目錄,比如:train
    String dir = "user-dir-prefix/";

    // 設置token的過期時間,這里設置的1分鍾
    long expireEndTime = System.currentTimeMillis() + 60*1000;
    Date expiration = new Date(expireEndTime);

    // 設置生成token的權限
    PolicyConditions policyConditions = new PolicyConditions();
    policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
    policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

    // 創建oss請求對象
    OSS client = new OSSClientBuilder().build(endpoint, accessId, accessKey);
    // 發送請求獲取token
    String postPolicy = client.generatePostPolicy(expiration, policyConditions);
    // 解析請求響應
    byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
    // 政策信息
    String encodedPolicy = BinaryUtil.toBase64String(binaryData);
    // 簽名信息
    String postSignature = client.calculatePostSignature(postPolicy);

    System.out.println("accessKeyId:"+accessId);
    System.out.println("encodedPolicy:"+encodedPolicy);
    System.out.println("postSignature:"+postSignature);
    System.out.println("dir:"+dir);
    System.out.println("host:"+host);
    System.out.println("expire:"+(expireEndTime / 1000));
}

注意需要將要訪問bucket設置為運行跨域。

STS臨時授權訪問OSS

在進行小文件的上傳時,比如圖片這些;使用上面簽名的方式完全夠用了;但是當我們需要上傳大文件的時候,比如上傳幾百兆、幾個G的文件時就不太適用了,因為這種大文件上傳肯定是比較慢的,為了用戶體驗我們應當提高其上傳速度,同時顯示一個上傳進度條。此時就需要用到分片上傳和斷點續傳這種方式了。

先說明下什么是分片上傳?分片上傳就是將一個文件拆分為多個小文件,然后再分別將小文件上傳到服務端,由於文件很小因此速度自然也就很快,服務端收到上傳完畢后會將所有的小文件合並成一個文件,這樣我們的文件就上傳完成了。

由於此種操作模式可能復雜,因此簽名的方式阿里雲並沒有提供分片上傳支持,而是提供了一個叫做STS臨時授權的功能。

使用STS臨時授權訪問OSS時請注意授予的權限,因此此種方式可以干更多的事情,因此建議縮小其可以訪問的文件夾權限。

STS臨時授權訪問OSS的流程圖:

STS臨時授權訪問OSS流程

首先我們需要在阿里雲做如下配置:

步驟一:創建RAM用戶

  • 登錄RAM控制台
  • 在左側導航欄的人員管理菜單下,單擊用戶。
  • 單擊新建用戶。
  • 輸入登錄名稱和顯示名稱。
  • 在訪問方式區域下,選擇編程訪問,然后單擊確定。
  • 單擊復制,保存訪問密鑰(AccessKey ID 和 AccessKey Secret)。

步驟二:為RAM用戶授予請求AssumeRole的權限

給我們剛剛創建的用戶授予AssumeRole的權限;之后我們就通過這個賬號來生成STS臨時授權的accessKeyId、accessKeySecret和token。

當然你也可以用你之前用來訪問OSS的那個賬號,但是為了保證安全,我們這里還是新建一個專門用來授權的賬號

  • 單擊已創建RAM用戶右側對應的添加權限。
  • 在添加權限頁面,選擇 AliyunSTSAssumeRoleAccess 權限;最后點擊確定按鈕。

步驟三:創建用於獲取臨時訪問憑證的角色

  • 在左側導航欄,單擊RAM角色管理。
  • 單擊創建RAM角色,選擇可信實體類型為阿里雲賬號,單擊下一步。
  • 在創建RAM角色頁面,填寫RAM角色名稱,選擇雲賬號為當前雲賬號。
  • 單擊完成。角色創建完成后,單擊關閉。
  • 之后在RAM角色管理頁面,找到剛剛創建的RAM角色,將其ARN值拷貝下來。(我們待會生成授權信息的時候需要)

步驟四:為角色授予上傳文件的權限

  • 在左側導航欄的權限管理菜單下,單擊權限策略管理。
  • 單擊創建權限策略。
  • 在新建自定義權限策略頁面,填寫策略名稱,配置模式選擇腳本配置,在里面可以進行相關的配置。下面這個是示例:
{
    "Version": "1",
    "Statement": [
     {
           "Effect": "Allow",
           "Action": [
             "oss:PutObject"
           ],
           "Resource": [
             "acs:oss:*:*:bucket-test/dir/*",
             "acs:oss:*:*:bucket-demo/train/*"
           ]
     }
    ]
}

配置文件標明授權其訪問 bucket名稱為bucket-test的名叫dir的目錄,以及bucket名稱為bucket-demo的名叫train的目錄。

由於我們使用STS授權時,通常是為了使用它的分片上傳,因此應當授予如下的操作(即完整的配置為):

{
    "Version": "1",
    "Statement": [
     {
           "Effect": "Allow",
           "Action": [
             "oss:PutObject",
             "oss:InitiateMultipartUpload",
             "oss:UploadPart",
             "oss:UploadPartCopy",
             "oss:CompleteMultipartUpload",
             "oss:AbortMultipartUpload",
             "oss:ListMultipartUploads",
             "oss:ListParts"
           ],
           "Resource": [
             "acs:oss:*:*:bucket-test/dir/*",
             "acs:oss:*:*:bucket-demo/train/*"
           ]
     }
    ]
}

最后我們需要將創建的這個策略綁定到RAM角色上面去才能生效(通過添加權限按鈕,然后在自定義策略里面找)。

使用Java的sdk生成授權信息

Java生成STS臨時授權的accessKeyId、accessKeySecret和token實現

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.profile.DefaultProfile;
import org.junit.Test;

public class OssStsTokenTest {

    @Test
    public void sstToken() {
        // 區域
        String regionId = "cn-chengdu";
        // OSS的ack
        String accessKeyId = "<yourAccessKeyId>";
        String accessKeySecret = "<yourAccessKeySecret>";

        // 創建OSSClient實例。
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);
        // 填寫步驟3獲取的角色ARN。
        String roleArn = "<yourARN>";
        // 標識臨時訪問憑證的名稱;這個可以按你需要隨便寫
        String roleSessionName = "<yourRoleSessionName>";

        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setRegionId(regionId);
        request.setRoleArn(roleArn);
        // 設置授權信息,注意如果這里沒有設置,那么默認會擁有上面設置的角色的權限
        request.setPolicy("{\n" +
                "    \"Version\": \"1\",\n" +
                "    \"Statement\": [\n" +
                "     {\n" +
                "           \"Effect\": \"Allow\",\n" +
                "           \"Action\": [\n" +
                "             \"oss:PutObject\"\n" +
                "           ],\n" +
                "           \"Resource\": [\n" +
                "             \"acs:oss:*:*:bucket-name/dir/*\"" +
                "           ]\n" +
                "     }\n" +
                "    ]\n" +
                "}");
        request.setRoleSessionName(roleSessionName);
        
        // 設置臨時訪問憑證的有效時間為3600秒。
        request.setDurationSeconds(3600L);
        try {
            AssumeRoleResponse response = client.getAcsResponse(request);
            System.out.println(JSONObject.toJSONString(response));
            AssumeRoleResponse.Credentials credentials = response.getCredentials();
            
            System.out.println(credentials.getAccessKeyId());
            System.out.println(credentials.getAccessKeySecret());
            System.out.println(credentials.getSecurityToken());
            System.out.println(credentials.getExpiration());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

這里返回給前端同學的信息中最好將過期時間也返回,這樣可以判斷是否過期以便可以主動獲取新的信息(上傳大文件時比較耗時)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM