簽名URL允許第三方使用者在沒有安全憑證或者授權的情況下進行上傳操作。第三方使用者使用簽名URL上傳檔案後,OSS將在指定的Bucket產生該檔案。
注意事項
產生PUT方法的簽名URL時,您必須具有
oss:PutObject
許可權。具體操作,請參見RAM Policy常見樣本。說明產生簽名URL過程中,SDK利用本機存放區的密鑰資訊,根據特定演算法計算出簽名(signature),然後將其附加到URL上,以確保URL的有效性和安全性。這一系列計算和構造URL的操作都是在用戶端完成,不涉及網路請求到服務端。因此,產生簽名URL時不需要授予調用者特定許可權。但是,為避免第三方使用者無法對簽名URL授權的資源執行相關操作,需要確保調用產生簽名URL介面的身份主體被授予對應的許可權。
產生私人檔案URL時涉及設定URL的有效時間長度。超出簽名URL設定的有效時間長度後,通過簽名URL上傳檔案時會提示簽名URL已到期,導致無法正常上傳檔案。如果您希望繼續使用簽名URL上傳檔案,需要重新擷取簽名URL。
簽名URL上傳不支援上傳FormData格式,若需使用FormData上傳資料,建議使用OSS表單上傳。
操作步驟
產生簽名URL。
以下僅列舉常見SDK的產生簽名URL的程式碼範例。關於其他SDK的產生簽名URL程式碼範例,請參見SDK簡介。
Java
import com.aliyun.oss.*; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import java.net.URL; import java.util.*; import java.util.Date; public class GetSignUrl { public static void main(String[] args) throws Throwable { // 以華東1(杭州)的外網Endpoint為例,其它Region請按實際情況填寫。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 填寫Bucket名稱,例如examplebucket。 String bucketName = "examplebucket"; // 填寫Object完整路徑,例如exampleobject.txt。Object完整路徑中不能包含Bucket名稱。 String objectName = "exampleobject.txt"; // 填寫Bucket所在地區。以華東1(杭州)為例,Region填寫為cn-hangzhou。 String region = "cn-hangzhou"; // 建立OSSClient執行個體。 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create() .endpoint(endpoint) .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region(region) .build(); URL signedUrl = null; try { // 指定產生的簽名URL到期時間,單位為毫秒。本樣本以設定到期時間為1小時為例。 Date expiration = new Date(new Date().getTime() + 3600 * 1000L); // 產生簽名URL。 GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT); // 設定到期時間。 request.setExpiration(expiration); // 通過HTTP PUT請求產生簽名URL。 signedUrl = ossClient.generatePresignedUrl(request); // 列印簽名URL。 System.out.println("signed url for putObject: " + signedUrl); } catch (OSSException oe) { System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason."); System.out.println("Error Message:" + oe.getErrorMessage()); System.out.println("Error Code:" + oe.getErrorCode()); System.out.println("Request ID:" + oe.getRequestId()); System.out.println("Host ID:" + oe.getHostId()); } catch (ClientException ce) { System.out.println("Caught an ClientException, which means the client encountered " + "a serious internal problem while trying to communicate with OSS, " + "such as not being able to access the network."); System.out.println("Error Message:" + ce.getMessage()); } } }
PHP
<?php if (is_file(__DIR__ . '/../autoload.php')) { require_once __DIR__ . '/../autoload.php'; } if (is_file(__DIR__ . '/../vendor/autoload.php')) { require_once __DIR__ . '/../vendor/autoload.php'; } use OSS\Credentials\EnvironmentVariableCredentialsProvider; use OSS\OssClient; use OSS\Core\OssException; use OSS\Http\RequestCore; use OSS\Http\ResponseCore; // 運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 $provider = new EnvironmentVariableCredentialsProvider(); // yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 $endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 填寫Bucket名稱。 $bucket= "examplebucket"; // 填寫不包含Bucket名稱在內的Object完整路徑。 $object = "exampleobject.txt"; // 設定簽名URL的有效時間長度為3600秒。 $timeout = 3600; try { $config = array( "provider" => $provider, "endpoint" => $endpoint, ); $ossClient = new OssClient($config); // 產生簽名URL。 $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT"); } catch (OssException $e) { printf(__FUNCTION__ . ": FAILED\n"); printf($e->getMessage() . "\n"); return; } print(__FUNCTION__ . ": signedUrl: " . $signedUrl . "\n");
Node.js
const OSS = require("ali-oss"); const { default: axios } = require("axios"); const fs = require("fs"); const client = new OSS({ // yourregion填寫Bucket所在地區。以華東1(杭州)為例,Region填寫為oss-cn-hangzhou。 region: "oss-cn-hangzhou", // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 accessKeyId: process.env.OSS_ACCESS_KEY_ID, accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET, // 填寫Bucket名稱。 bucket: "examplebucket", }); // 組建檔案的簽名URL。 const url = client.signatureUrl("exampleobject.txt", { method: "PUT", "Content-Type": "application/x-www-form-urlencoded", }); console.log(url);
Python
# -*- coding: utf-8 -*- import oss2 from oss2.credentials import EnvironmentVariableCredentialsProvider # 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider()) # 填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。 endpoint = "https://oss-cn-hangzhou.aliyuncs.com" # 填寫Endpoint對應的Region資訊,例如cn-hangzhou。注意,v4簽名下,必須填寫該參數 region = "cn-hangzhou" # yourBucketName填寫儲存空間名稱。 bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region) # 填寫Object完整路徑,例如exampledir/exampleobject.txt。Object完整路徑中不能包含Bucket名稱。 object_name = 'exampledir/exampleobject.txt' # 產生上傳檔案的簽名URL,有效時間為60秒。 # 產生簽名URL時,OSS預設會對Object完整路徑中的正斜線(/)進行轉義,從而導致產生的簽名URL無法直接使用。 # 設定slash_safe為True,OSS不會對Object完整路徑中的正斜線(/)進行轉義,此時產生的簽名URL可以直接使用。 url = bucket.sign_url('PUT', object_name, 60, slash_safe=True) print('簽名URL的地址為:', url)
Android
// 填寫Bucket名稱,例如examplebucket。 String bucketName = "examplebucket"; // 填寫不包含Bucket名稱在內源Object的完整路徑,例如exampleobject.txt。 String objectKey = "exampleobject.txt"; // 設定content-type。 String contentType = "application/octet-stream"; String url = null; try { // 產生用於上傳檔案的簽名URL。 GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey); // 設定簽名URL的到期時間為30分鐘。 request.setExpiration(30*60); request.setContentType(contentType); request.setMethod(HttpMethod.PUT); url = oss.presignConstrainedObjectURL(request); Log.d("url", url); } catch (ClientException e) { e.printStackTrace(); }
Go
package main import ( "context" "flag" "log" "time" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" ) // 定義全域變數 var ( region string // 儲存地區 bucketName string // 儲存空間名稱 objectName string // 對象名稱 ) // init函數用於初始化命令列參數 func init() { flag.StringVar(®ion, "region", "", "The region in which the bucket is located.") flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.") flag.StringVar(&objectName, "object", "", "The name of the object.") } func main() { // 解析命令列參數 flag.Parse() // 檢查bucket名稱是否為空白 if len(bucketName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, bucket name required") } // 檢查region是否為空白 if len(region) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, region required") } // 檢查object名稱是否為空白 if len(objectName) == 0 { flag.PrintDefaults() log.Fatalf("invalid parameters, object name required") } // 載入預設配置並設定憑證提供者和地區 cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region) // 建立OSS用戶端 client := oss.NewClient(cfg) // 產生PutObject的預簽名URL result, err := client.Presign(context.TODO(), &oss.PutObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), //ContentType: oss.Ptr("text/txt"), // 請確保在服務端產生該簽名URL時設定的ContentType與在使用URL時設定的ContentType一致 //Metadata: map[string]string{"key1": "value1", "key2": "value2"}, // 請確保在服務端產生該簽名URL時設定的Metadata與在使用URL時設定的Metadata一致 }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("failed to put object presign %v", err) } log.Printf("request method:%v\n", result.Method) log.Printf("request expiration:%v\n", result.Expiration) log.Printf("request url:%v\n", result.URL) if len(result.SignedHeaders) > 0 { //當返回結果包含簽名頭時,使用簽名URL發送Put請求時,需要設定相應的要求標頭 log.Printf("signed headers:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
iOS
// 填寫Bucket名稱。 NSString *bucketName = @"examplebucket"; // 填寫Object名稱。 NSString *objectKey = @"exampleobject.txt"; NSURL *file = [NSURL fileURLWithPath:@"<filePath>"]; NSString *contentType = [OSSUtil detemineMimeTypeForFilePath:file.absoluteString uploadName:objectKey]; __block NSString *urlString; // 產生用於上傳的簽名URL,並指定簽名URL到期時間為30分鐘。 OSSTask *task = [client presignConstrainURLWithBucketName:bucketName withObjectKey:objectKey httpMethod:@"PUT" withExpirationInterval:30 * 60 withParameters:@{} contentType:contentType contentMd5:nil]; [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) { if (task.error) { NSLog(@"presign error: %@", task.error); } else { urlString = task.result; NSLog(@"url: %@", urlString); } return nil; }];
使用簽名URL上傳檔案。
以下僅列舉常見SDK使用簽名URL簡單上傳的程式碼範例。關於其他SDK使用簽名URL簡單上傳的程式碼範例,請參見SDK簡介。
Java
import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import java.io.*; import java.net.URL; import java.util.*; public class SignUrlUpload { public static void main(String[] args) throws Throwable { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; // 將<signedUrl>替換為授權URL。 URL signedUrl = new URL("<signedUrl>"); // 填寫本地檔案的完整路徑。如果未指定本地路徑,則預設從樣本程式所屬專案對應本地路徑中上傳檔案。 String pathName = "C:\\Users\\demo.txt"; try { HttpPut put = new HttpPut(signedUrl.toString()); System.out.println(put); HttpEntity entity = new FileEntity(new File(pathName)); put.setEntity(entity); httpClient = HttpClients.createDefault(); response = httpClient.execute(put); System.out.println("返回上傳狀態代碼:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("使用網路程式庫上傳成功"); } System.out.println(response.toString()); } catch (Exception e){ e.printStackTrace(); } finally { response.close(); httpClient.close(); } } }
PHP
<?php if (is_file(__DIR__ . '/../autoload.php')) { require_once __DIR__ . '/../autoload.php'; } if (is_file(__DIR__ . '/../vendor/autoload.php')) { require_once __DIR__ . '/../vendor/autoload.php'; } use OSS\Http\RequestCore; use OSS\Http\ResponseCore; // 填寫步驟1產生的簽名URL。 $signedUrl = 'yourSignedUrl'; $content = "Hello OSS"; $request = new RequestCore($signedUrl); // 使用簽名URL上傳檔案。 $request->set_method('PUT'); $request->add_header('Content-Type', ''); $request->add_header('Content-Length', strlen($content)); $request->set_body($content); $request->send_request(); $res = new ResponseCore($request->get_response_header(), $request->get_response_body(), $request->get_response_code()); if ($res->isOK()) { print(__FUNCTION__ . ": OK" . "\n"); } else { print(__FUNCTION__ . ": FAILED" . "\n"); };
Node.js
const OSS = require("ali-oss"); const { default: axios } = require("axios"); const fs = require("fs"); // 填寫步驟1產生的簽名URL。 const url = "yourSignedUrl"; // 指定本地檔案的完整路徑。 const file = fs.readFileSync("D:\\examplefile.txt"); // 使用簽名URL上傳檔案。 axios({ url, method: "PUT", data: file, }) .then((r) => console.log(r)) .catch((e) => console.log(e));
Python
import requests def upload_file(signed_url, file_path): try: # 開啟檔案 with open(file_path, 'rb') as file: # 發送PUT請求上傳檔案 response = requests.put(signed_url, data=file) print(f"返回上傳狀態代碼:{response.status_code}") if response.status_code == 200: print("使用網路程式庫上傳成功") print(response.text) except Exception as e: print(f"發生錯誤:{e}") if __name__ == "__main__": # 將<signedUrl>替換為授權URL。 signed_url = "<signedUrl>" # 填寫本地檔案的完整路徑。如果未指定本地路徑,則預設從樣本程式所屬專案對應本地路徑中上傳檔案。 file_path = "C:\\Users\\demo.txt" upload_file(signed_url, file_path)
Browser.js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.18.0.min.js"></script> <script> // 填寫步驟1產生的簽名URL。 const url = "yourSignatureUrl"; var xhr = new XMLHttpRequest(); xhr.open("PUT", url, true); xhr.onload = function () { // 請求結束後,在此處編寫處理代碼。 }; // xhr.send(null); xhr.send("string"); // xhr.send(new Blob()); // xhr.send(new Int8Array()); // xhr.send({ form: 'data' }); // xhr.send(document); </script> </body> </html>
Android
// 填寫產生的簽名URL。 String url = ""; // 指定本地檔案的完整路徑。 String localFile = "/storage/emulated/0/oss/examplefile"; // 設定content-type。 String contentType = "application/octet-stream"; // 通過簽名URL上傳檔案。 OkHttpClient client = new OkHttpClient(); Request putRequest = new Request.Builder() .url(url) .put(RequestBody.create(MediaType.parse(contentType), new File(localFile))) .build(); client.newCall(putRequest).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d("response", response.body().string()); } });
Go
package main import ( "fmt" "io" "net/http" "os" ) func uploadFile(signedUrl, filePath string) error { // 開啟檔案 file, err := os.Open(filePath) if err != nil { return fmt.Errorf("無法開啟檔案: %w", err) } defer file.Close() // 建立一個新的HTTP用戶端 client := &http.Client{} // 建立一個PUT請求 req, err := http.NewRequest("PUT", signedUrl, file) if err != nil { return fmt.Errorf("建立請求失敗: %w", err) } // 發送請求 resp, err := client.Do(req) if err != nil { return fmt.Errorf("發送請求失敗: %w", err) } defer resp.Body.Close() // 讀取響應 body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("讀取響應失敗: %w", err) } fmt.Printf("返回上傳狀態代碼: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("使用網路程式庫上傳成功") } fmt.Println(string(body)) return nil } func main() { // 將<signedUrl>替換為授權URL。 signedUrl := "<signedUrl>" // 填寫本地檔案的完整路徑。如果未指定本地路徑,則預設從樣本程式所屬專案對應本地路徑中上傳檔案。 filePath := "C:\\Users\\demo.txt" err := uploadFile(signedUrl, filePath) if err != nil { fmt.Println("發生錯誤:", err) } }
iOS
// 通過簽名URL上傳檔案。 NSURL * url = [NSURL URLWithString:urlString]; NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"PUT"; request.allHTTPHeaderFields = @{OSSHttpHeaderContentType: contentType}; NSURLSession * session = [NSURLSession sharedSession]; NSURLSessionTask * sessionTask = [session uploadTaskWithRequest:request fromFile:file completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { NSLog(@"upload error: %@", error); return; } else if (((NSHTTPURLResponse*)response).statusCode == 203 || ((NSHTTPURLResponse*)response).statusCode >= 300) { NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"upload error: %@", body); return; } NSLog(@"upload success"); }]; [sessionTask resume];
相關文檔
當您希望使用簽名URL以分區上傳的方式上傳大檔案到OSS時,您需要先初始化分區上傳,然後把每一個分區產生一個對應的上傳簽名URL,並返回給第三方應用。第三方應用可以使用這些簽名URL上傳所有的分區資訊,然後合并分區來達到通過簽名URL實現分區上傳的目的。關於產生分區上傳的簽名URL以及使用簽名URL臨時授權分區上傳的程式碼範例,請參見使用簽名URL下載。