阿里雲OSS檔案上傳前端搭配之後端的活
雖然不用後端額外的處理,前端也可以根據阿里雲的提供的方法直接操作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();
}
}
}
這裡返回給前端同學的資訊中最好將過期時間也返回,這樣可以判斷是否過期以便可以主動獲取新的資訊(上傳大檔案時比較耗時)。