デフォルトでは、Object Storage Service (OSS) バケット内のオブジェクトのアクセス制御リスト (ACL) は非公開です。 オブジェクト所有者のみがオブジェクトにアクセスする権限を持っています。 このトピックでは、Go 用 OSS SDK を使用して、HTTP GET リクエストを許可し、有効期間を持つ署名付き URL を生成し、その署名付き URL をユーザーと共有して、ユーザーが一時的にオブジェクトをダウンロードできるようにする方法について説明します。 有効期間内であれば、ユーザーはオブジェクトを繰り返しダウンロードできます。 有効期限が過ぎると、ユーザーは新しい署名付き URL を取得する必要があります。
注意事項
このトピックのサンプルコードでは、中国 (杭州) リージョンのリージョン ID
cn-hangzhou
を使用しています。 デフォルトでは、パブリックエンドポイントを使用してバケット内のリソースにアクセスします。 バケットが配置されているのと同じリージョン内の他の Alibaba Cloud サービスからバケット内のリソースにアクセスする場合は、内部エンドポイントを使用します。 OSS のリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。このトピックでは、アクセス認証情報は環境変数から取得されます。 アクセス認証情報を構成する方法の詳細については、「アクセス認証情報を構成する」をご参照ください。
権限がなくても署名付き URL を生成できます。 ただし、
oss:GetObject
権限を持っている場合にのみ、サードパーティは署名付き URL を使用してオブジェクトをダウンロードできます。 権限を付与する方法の詳細については、「RAM ユーザーにカスタム権限を付与する」をご参照ください。このトピックでは、最長 7 日間の有効期間を持つ V4 署名付き URL が使用されます。 詳細については、「(推奨) URL に V4 署名を含める」をご参照ください。
プロセス
次のフローチャートは、署名付き URL を使用してオブジェクトをダウンロードする方法を示しています。
操作構文
特定の操作を呼び出して署名付き URL を生成し、署名付き URL を使用してバケット内のオブジェクトに一時的なアクセス権限を付与できます。 URL の有効期限が切れるまで、署名付き URL を複数回使用できます。
構文
func (c *Client) Presign(ctx context.Context, request any, optFns ...func(*PresignOptions)) (result *PresignResult, err error)
リクエストパラメーター
パラメーター | タイプ | 説明 |
ctx | context.Context | リクエストのコンテキスト。 |
request | *GetObjectRequest | 署名付き URL の生成に使用する API 操作の名前。 |
optFns | ...func(*PresignOptions) | 署名付き URL の有効期間。 このパラメーターを指定しない場合、署名付き URL はデフォルト値である 15 分を使用します。 このパラメーターはオプションです。 |
PressignOptions
オプション | タイプ | 説明 |
Expires | time.Duration | 署名付き URL の有効期間。 たとえば、有効期間を 30 分に設定するには、Expires を 30 * time.Minute に設定します。 |
Expiration | time.Time | 署名付き URL の絶対有効期限。 |
V4 署名アルゴリズムを使用する場合、有効期間は最大 7 日間です。 Expiration と Expires の両方を指定した場合、Expiration が優先されます。
レスポンスパラメーター
パラメーター | タイプ | 説明 |
result | *PresignResult | 署名付き URL、HTTP メソッド、有効期間、リクエストで指定されたリクエストヘッダーなど、返された結果。 |
err | error | リクエストのステータス。 リクエストが失敗した場合、err の値は nil になりません。 |
PresignResult のレスポンスパラメーター
パラメーター | タイプ | 説明 |
Method | string | 操作に対応する HTTP メソッド。 たとえば、GetObject 操作の HTTP メソッドは GET です。 |
URL | string | 署名付き URL。 |
Expiration | time.Time | 署名付き URL の有効期限。 |
SignedHeaders | map[string]string | リクエストで指定されたリクエストヘッダー。 たとえば、Content-Type ヘッダーの値が指定されている場合は、Content-Type に関する情報が返されます。 |
サンプルコード
次のサンプルコードは、オブジェクト所有者が HTTP GET リクエストを許可する署名付き URL を生成する方法の例を示しています。
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", "", "バケットが配置されているリージョン。") flag.StringVar(&bucketName, "bucket", "", "バケットの名前。") flag.StringVar(&objectName, "object", "", "オブジェクトの名前。") } func main() { // コマンドラインパラメーターを解析します。 flag.Parse() // バケット名が空かどうかを確認します。 if len(bucketName) == 0 { flag.PrintDefaults() log.Fatalf("無効なパラメーター、バケット名が必要です") } // リージョンが空かどうかを確認します。 if len(region) == 0 { flag.PrintDefaults() log.Fatalf("無効なパラメーター、リージョンが必要です") } // オブジェクト名が空かどうかを確認します。 if len(objectName) == 0 { flag.PrintDefaults() log.Fatalf("無効なパラメーター、オブジェクト名が必要です") } // デフォルトの構成を読み込み、認証情報プロバイダーとリージョンを指定します。 cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region) // OSS クライアントを作成します。 client := oss.NewClient(cfg) // GetObject リクエストの署名付き URL を生成します。 result, err := client.Presign(context.TODO(), &oss.GetObjectRequest{ Bucket: oss.Ptr(bucketName), Key: oss.Ptr(objectName), }, oss.PresignExpires(10*time.Minute), ) if err != nil { log.Fatalf("オブジェクトの署名付き URL の取得に失敗しました %v", err) } log.Printf("リクエストメソッド: %v\n", result.Method) log.Printf("リクエストの有効期限: %v\n", result.Expiration) log.Printf("リクエスト URL: %v\n", result.URL) if len(result.SignedHeaders) > 0 { // HTTP GET リクエストを許可する署名付き URL を生成するときにリクエストヘッダーを指定する場合は、署名付き URL を使用して開始された GET リクエストにリクエストヘッダーが含まれていることを確認してください。 これにより、リクエストの失敗と署名エラーを防ぎます。 log.Printf("署名済みヘッダー:\n") for k, v := range result.SignedHeaders { log.Printf("%v: %v\n", k, v) } } }
次のサンプルコードは、サードパーティユーザーが HTTP GET リクエストを許可する署名付き URL を使用してオブジェクトをダウンロードする方法の例を示しています。
Curl
curl -SO "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"
Java
import java.io.BufferedInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class Demo { public static void main(String[] args) { // HTTP GET リクエストを許可する署名付き URL に置き換えます。 String fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; // ダウンロードしたオブジェクトを保存するパスを、オブジェクト名と拡張子を含めて指定します。 String savePath = "C:/downloads/myfile.txt"; try { downloadFile(fileURL, savePath); System.out.println("ダウンロードが完了しました!"); } catch (IOException e) { System.err.println("ダウンロード中にエラーが発生しました: " + e.getMessage()); } } private static void downloadFile(String fileURL, String savePath) throws IOException { URL url = new URL(fileURL); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestMethod("GET"); // レスポンスコードを指定します。 int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { // 入力ストリームを構成します。 InputStream inputStream = new BufferedInputStream(httpConn.getInputStream()); // 出力ストリームを構成します。 FileOutputStream outputStream = new FileOutputStream(savePath); byte[] buffer = new byte[4096]; // バッファーのサイズを指定します。 int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.close(); inputStream.close(); } else { System.out.println("ダウンロードするファイルがありません。 サーバーは HTTP コードを返信しました: " + responseCode); } httpConn.disconnect(); } }
Node.js
const https = require('https'); const fs = require('fs'); const fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; const savePath = "C:/downloads/myfile.txt"; https.get(fileURL, (response) => { if (response.statusCode === 200) { const fileStream = fs.createWriteStream(savePath); response.pipe(fileStream); fileStream.on('finish', () => { fileStream.close(); console.log("ダウンロードが完了しました!"); }); } else { console.error(`ダウンロードに失敗しました。 サーバーはコードで応答しました: ${response.statusCode}`); } }).on('error', (err) => { console.error("ダウンロード中にエラーが発生しました:", err.message); });
Python
import requests file_url = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************" save_path = "C:/downloads/myfile.txt" try: response = requests.get(file_url, stream=True) if response.status_code == 200: with open(save_path, 'wb') as f: for chunk in response.iter_content(4096): f.write(chunk) print("ダウンロードが完了しました!") else: print(f"ダウンロードするファイルがありません。 サーバーは HTTP コードを返信しました: {response.status_code}") except Exception as e: print("ダウンロード中にエラーが発生しました:", e)
Go
package main import ( "io" "net/http" "os" ) func main() { fileURL := "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************" savePath := "C:/downloads/myfile.txt" response, err := http.Get(fileURL) if err != nil { panic(err) } defer response.Body.Close() if response.StatusCode == http.StatusOK { outFile, err := os.Create(savePath) if err != nil { panic(err) } defer outFile.Close() _, err = io.Copy(outFile, response.Body) if err != nil { panic(err) } println("ダウンロードが完了しました!") } else { println("ダウンロードするファイルがありません。 サーバーは HTTP コードを返信しました:", response.StatusCode) } }
JavaScript
const fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; const savePath = "C:/downloads/myfile.txt"; // ダウンロードしたオブジェクトの名前を指定します。 fetch(fileURL) .then(response => { if (!response.ok) { throw new Error(`サーバーは HTTP コードを返信しました: ${response.status}`); } return response.blob(); // レスポンスのタイプを blob に変更します。 }) .then(blob => { const link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = savePath; // ダウンロードしたオブジェクトの名前を指定します。 document.body.appendChild(link); // この手順により、署名付き URL がドキュメントに存在することが保証されます。 link.click(); // 署名付き URL をクリックして、オブジェクトのダウンロードをシミュレートします。 link.remove(); // オブジェクトのダウンロード後、署名付き URL を削除します。 console.log("ダウンロードが完了しました!"); }) .catch(error => { console.error("ダウンロード中にエラーが発生しました:", error); });
Android-Java
import android.os.AsyncTask; import android.os.Environment; import java.io.BufferedInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class DownloadTask extends AsyncTask<String, String, String> { @Override protected String doInBackground(String... params) { String fileURL = params[0]; String savePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/myfile.txt"; // ダウンロードしたオブジェクトを保存するパスを指定します。 try { URL url = new URL(fileURL); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestMethod("GET"); int responseCode = httpConn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { InputStream inputStream = new BufferedInputStream(httpConn.getInputStream()); FileOutputStream outputStream = new FileOutputStream(savePath); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.close(); inputStream.close(); return "ダウンロードが完了しました!"; } else { return "ダウンロードするファイルがありません。 サーバーは HTTP コードを返信しました: " + responseCode; } } catch (Exception e) { return "ダウンロード中にエラーが発生しました: " + e.getMessage(); } } }
Objective-C
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // 署名付き URL とオブジェクトを保存するパスを指定します。 NSString *fileURL = @"https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"; NSString *savePath = @"/Users/your_username/Desktop/myfile.txt"; // your_username をユーザー名に置き換えます。 // URL オブジェクトを作成します。 NSURL *url = [NSURL URLWithString:fileURL]; // オブジェクトダウンロードタスクを作成します。 NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // エラーを処理します。 if (error) { NSLog(@"ダウンロード中にエラーが発生しました: %@", error.localizedDescription); return; } // オブジェクトのデータを確認します。 if (!data) { NSLog(@"データを受信していません。"); return; } // オブジェクトを保存します。 NSError *writeError = nil; BOOL success = [data writeToURL:[NSURL fileURLWithPath:savePath] options:NSDataWritingAtomic error:&writeError]; if (success) { NSLog(@"ダウンロードが完了しました!"); } else { NSLog(@"ファイルの保存中にエラーが発生しました: %@", writeError.localizedDescription); } }]; // オブジェクトダウンロードタスクを開始します。 [task resume]; // メインスレッドを実行し続けて、非同期リクエストを完了します。 [[NSRunLoop currentRunLoop] run]; } return 0; }