PostObject 操作を使用して、Web クライアントから Object Storage Service (OSS) にオブジェクトを直接アップロードできます。アップロードコールバックを設定することもできます。サーバーによって生成された署名は、直接アップロードの安全な転送を保証します。また、アップロードポリシーを設定してアップロード操作を制限し、ビジネス要件を満たすこともできます。
ソリューション概要
次の図は、アプリケーションサーバーで署名を生成し、Web クライアントから OSS にファイルを直接アップロードする方法を示しています。
リクエストへの署名追加、OSS へのオブジェクトのアップロード、アップロードコールバックの設定を行うには、次の手順を実行します。
このプロセスでは、一時的なアクセス認証情報が使用されます。これにより、アプリケーションサーバーの AccessKey ペアの漏洩を防ぎ、アップロードプロセス中のオブジェクトのセキュリティを確保します。
OSS の設定:OSS コンソールでバケットを作成し、ユーザーがアップロードしたオブジェクトを保存します。バケットにオリジン間リソース共有 (CORS) ルールを設定して、Web クライアントからのクロスオリジンリクエストを許可します。
サーバーの設定:アクセス認証情報と、バケット名、ディレクトリパス、有効期限などの事前に設定されたアップロードポリシーを使用して署名を生成します。この署名は、ユーザーが特定の期間内にオブジェクトをアップロードすることを承認します。
Web クライアントの設定:HTML フォームを構築し、オブジェクトを OSS に直接アップロードします。OSS はクライアントのアップロードコールバック設定を解析し、POST コールバックリクエストをアプリケーションサーバーに送信します。
サンプルプロジェクト
完全な Java サンプルプロジェクトについては、「server-signed-direct-upload-callback-java.zip」をご参照ください。
完全な Python サンプルプロジェクトについては、「server-signed-direct-upload-callback-python.zip」をご参照ください。
完全な Node.js サンプルプロジェクトについては、「server-signed-direct-upload-callback-nodejs.zip」をご参照ください。
完全な Go サンプルプロジェクトについては、「server-signed-direct-upload-callback-go.zip」をご参照ください。
完全な PHP サンプルプロジェクトについては、「server-signed-direct-upload-callback-php.zip」をご参照ください。
操作手順
ステップ 1:OSS の設定
1. バケットの作成
Web アプリケーションがブラウザからアップロードしたデータを保存するために、OSS バケットを作成します。
OSS コンソールにログインします。
左側のナビゲーションウィンドウで、バケット をクリックし、次に バケットの作成 をクリックします。
バケットの作成 パネルで、[クイック作成] を選択し、次のパラメーターを設定します。
パラメーター
値の例
バケット名
web-direct-upload- callback
リージョン
中国 (杭州)
OK をクリックします。
2. CORS ルールの設定
作成したバケットに CORS ルールを設定します。
[バケットリスト] ページに移動し、バケット名をクリックします。
クロスオリジンリソース共有の設定 ページで、ルールの作成 をクリックします。
ルールの作成 パネルで、次の情報に基づいて CORS ルールを設定します。
パラメーター
値の例
ソース
*
許可されたメソッド
POST、PUT、GET
許可されたヘッダー
*
OK をクリックします。
ステップ 2:サーバーの設定
すでにビジネスサーバーをお持ちの場合は、準備をスキップして 1. ユーザー権限の設定 に進むことができます。
準備:ビジネスサーバーとして Elastic Compute Service (ECS) インスタンスを作成
操作 1:ECS インスタンスの作成
[カスタム起動] ページに移動し、次の情報に基づいて ECS インスタンスを購入するために必要な基本リソースを作成または選択します。
リージョンと課金方法の選択
ビジネス要件に基づいて課金方法を選択します。このトピックでは、より柔軟な従量課金方式を選択します。
ネットワーク遅延の要件に基づいてリージョンを選択します。ほとんどの場合、ネットワーク遅延を低減し、アクセス速度を向上させるために、ユーザーに近いリージョンを選択することを推奨します。このトピックでは、中国 (杭州) を選択します。

Virtual Private Cloud (VPC) と vSwitch の作成
VPC を作成する際に、ECS インスタンスを作成するリージョンを選択し、ビジネス要件に基づいて CIDR ブロックを計画します。このトピックでは、中国 (杭州) リージョンに VPC と vSwitch を作成します。VPC を作成した後、ECS コンソールのインスタンス購入ページの [カスタム起動] タブに戻り、VPC と vSwitch のドロップダウンリストを更新して、作成した VPC と vSwitch を選択します。
説明VPC の作成時に vSwitch を作成することもできます。



インスタンスタイプとイメージの選択
インスタンスタイプとイメージを選択します。インスタンスの作成時に、イメージに含まれるオペレーティングシステムのバージョンがインスタンスにインストールされます。この Topic では、テスト要件を満たし費用対効果が高い
ecs.e-c1m1.largeインスタンスタイプと、Alibaba Cloud Linux 3.2104 LTS 64 ビットパブリックイメージを選択します。
ストレージの選択
ビジネス要件に基づいて、ECS インスタンスのシステムディスクとデータディスクを設定します。このデモプロジェクトは軽量な Web アプリケーションをデプロイするため、システムディスクだけで十分であり、データディスクは設定しません。

パブリック IP アドレスの割り当て
ECS インスタンスにインターネット接続を提供するには、[パブリック IPv4 アドレスの割り当て] を選択して、インスタンスにパブリック IP アドレスを割り当てます。インスタンス作成後に Elastic IP Address (EIP) をインスタンスに関連付けることもできます。詳細については、「EIP をクラウドリソースに関連付ける」をご参照ください。
説明ECS インスタンスにパブリック IP アドレスを割り当てない、または EIP を関連付けない場合、SSH または RDP (Remote Desktop Protocol) 経由でインスタンスにアクセスしたり、インスタンスにデプロイされた Web サービスをインターネット経由でテストしたりすることはできません。
このトピックでは、ネットワーク使用量の課金方法として [トラフィック課金] を選択します。トラフィック課金方式では、インターネット経由で転送されたデータ量に基づいて課金されます。詳細については、「パブリック帯域幅の課金」をご参照ください。

セキュリティグループの作成
ECS インスタンスのセキュリティグループを作成します。セキュリティグループは、ECS インスタンスのインバウンドトラフィックとアウトバウンドトラフィックを制御できる仮想ファイアウォールとして機能します。セキュリティグループを作成する際は、ECS インスタンスへのアクセスを許可するために次のポートを開きます。
ポート範囲:SSH (22)、RDP (3389)、HTTP (80)、HTTPS (443)。
説明[ポート範囲] パラメーターは、ECS インスタンスで実行されるアプリケーションに対して開く必要があるポートを指定します。
デフォルトでは、ソースアドレスとして 0.0.0.0/0 を参照するルールが新しいセキュリティグループに作成されます。0.0.0.0/0 はすべての IP アドレスを表します。このルールにより、指定されたポートで、すべての IP アドレスから ECS インスタンスへのアクセスが許可されます。インスタンスを作成した後、特定の IP アドレスからのみインスタンスへのアクセスを許可するようにルールを変更することを推奨します。詳細については、「セキュリティグループルールの変更」をご参照ください。

キーペアの作成
キーペアは、ECS インスタンスにログインする際に ID を検証するために使用される安全な認証情報です。ECS インスタンスに接続する際に将来使用するために、キーペアを作成した後、秘密鍵をダウンロードする必要があります。キーペアを作成した後、インスタンス購入ページの [カスタム起動] タブに戻り、[キーペア] ドロップダウンリストを更新して、作成したキーペアを選択します。
rootユーザーは、オペレーティングシステム上で最高の権限を持ちます。rootをログインユーザー名として使用すると、セキュリティリスクにつながる可能性があります。ログインユーザー名としてecs-userを選択することをお勧めします。説明キーペアを作成すると、秘密鍵が自動的にダウンロードされます。ブラウザのダウンロード履歴を確認し、
.pem秘密鍵ファイルを保存してください。
ECS インスタンスの作成と表示
ECS インスタンスに必要な基本リソースを作成または選択した後、[注文の作成] をクリックします。表示されるメッセージで、[管理コンソール] をクリックして、コンソールで作成された ECS インスタンスを表示します。後で使用するために、次のデータを記録します。
インスタンス ID:インスタンスリストでインスタンスをクエリするために使用します。
リージョン:インスタンスリストでインスタンスをクエリするために使用します。
パブリック IP アドレス:ECS インスタンス上の Web サービスのデプロイメントを検証するために使用します。


操作 2:ECS インスタンスへの接続
ECS コンソールの [インスタンス] ページで、リージョンとインスタンス ID に基づいて作成した ECS インスタンスを見つけます。[操作] 列の [リモート接続] をクリックします。

[リモート接続] ダイアログボックスで、[Workbench を使用してインスタンスに接続] の横にある [今すぐ接続] をクリックします。

[インスタンスにログイン] ダイアログボックスで、[接続方法] を [ターミナル接続] に、[認証方法] を [SSH キーペア認証] に設定します。 キーペアを作成したときにダウンロードした秘密鍵ファイルを入力またはアップロードします。 次に [ログイン] をクリックすると、
ecs-userユーザーとして ECS インスタンスにログインできます。説明キーペアを作成すると、秘密鍵ファイルがお使いのコンピューターに自動的にダウンロードされます。ブラウザのダウンロード履歴を確認し、
.pem秘密鍵ファイルを見つけてください。次のページが表示された場合、ECS インスタンスにログインしています。

1. ユーザー権限の設定
デプロイメント完了後に、権限のない操作が原因でローカルファイルのアップロードが失敗するのを防ぐために、次の手順を実行して Resource Access Management (RAM) ユーザーを作成し、RAM ユーザーに必要な権限を付与することを推奨します。
操作 1:RAM で RAM ユーザーを作成
RAM ユーザーを作成し、RAM ユーザーの AccessKey ペアを取得します。AccessKey ペアは、アプリケーションへのアクセスと管理に必要な長期的なアクセス認証情報です。
Alibaba Cloud アカウントまたはアカウント管理者として RAM コンソールにログインします。
左側のナビゲーションウィンドウで、[ID 管理] > [ユーザー] を選択します。
[ユーザーの作成] をクリックします。
[ログイン名] と [表示名] を入力します。
[アクセスモード] セクションで、[プログラムによるアクセス] を選択し、[OK] をクリックします。
RAM ユーザーの AccessKey Secret は、RAM ユーザーを作成するときにのみ取得できます。認証情報の漏洩を防ぐため、AccessKey Secret を安全に保管してください。
[操作] 列の [コピー] をクリックして、AccessKey ペア (AccessKey ID と AccessKey Secret) を保存します。
操作 2:RAM で RAM ユーザーに AssumeRole 操作を呼び出す権限を付与
RAM ユーザーに Security Token Service (STS) の AssumeRole 操作を呼び出す権限を付与します。これにより、RAM ユーザーは RAM ロールを引き受けて STS トークンを取得できます。
左側のナビゲーションウィンドウで、[ID 管理] > [ユーザー] を選択します。
[ユーザー] ページで、RAM ユーザーを見つけ、[操作] 列の [権限の追加] をクリックします。
[権限の追加] ページで、[AliyunSTSAssumeRoleAccess] システムポリシーを選択します。
説明STS の AssumeRole 操作を呼び出すために必要な固定権限は [AliyunSTSAssumeRoleAccess] です。この権限は、一時的なアクセス認証情報を取得し、その一時的なアクセス認証情報を使用して OSS にリクエストを送信するために必要な権限とは関係ありません。
[OK] をクリックします。
操作 3:RAM で RAM ロールを作成
Alibaba Cloud アカウント用の RAM ロールを作成し、RAM ロールの Alibaba Cloud リソースネーム (ARN) を取得します。RAM ユーザーはこの RAM ロールを引き受けることができます。
左側のナビゲーションウィンドウで、[ID 管理] > [ロール] を選択します。
[ロールの作成] をクリックします。[信頼できるエンティティの選択] セクションで、[Alibaba Cloud アカウント] を選択します。
[現在の Alibaba Cloud アカウント] を選択し、[OK] をクリックします。
ロール名を入力し、[OK] をクリックします。
[RAM ロール管理] ページで、[コピー] をクリックして RAM ロールの ARN を保存します。
操作 4:RAM でアップロードファイルアクセス ポリシーを作成
最小権限の原則に基づいてカスタムポリシーを作成し、RAM ロールに特定のバケットにのみデータをアップロードする権限を付与します。
左側のナビゲーションウィンドウで、[権限管理] > [ポリシー] を選択します。
[ポリシーの作成] をクリックします。
[ポリシーの作成] ページで、[スクリプト] をクリックします。 以下のスクリプトの
<BucketName>を、準備で作成したバケットの名前であるweb-direct-uploadに置き換えます。{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "oss:PutObject", "Resource": "acs:oss:*:*:<BucketName>/*" } ] }ポリシーを設定した後、[OK] をクリックします。
[ポリシーの作成] ダイアログボックスで、[ポリシー名] を入力し、[OK] をクリックします。
操作 5:RAM で RAM ロールに権限を付与
カスタムポリシーを RAM ロールにアタッチします。これにより、RAM ロールが引き受けられたときに、RAM ロールが必要な権限を提供できるようになります。
左側のナビゲーションウィンドウで、[ID 管理] > [ロール] を選択します。
[ロール] ページで、RAM ロールを見つけ、[操作] 列の [権限の追加] をクリックします。
[権限の追加] ページで、[カスタムポリシー] を選択し、作成したカスタムポリシーを選択します。
[OK] をクリックします。
2. アプリケーションサーバーでの一時的なアクセス認証情報の取得と署名の計算
コードでの明示的な構成を避け、漏洩のリスクを低減するために、accessKeyId、accessKeySecret、およびroleArn などの機密情報を環境変数として構成することをお勧めします。
次の手順で環境変数を追加できます。
Linux オペレーティングシステム
コマンドラインインターフェイスで次のコマンドを実行して、環境変数を
~/.bashrcファイルに追加します。echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.bashrc echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.bashrc echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.bashrc次のコマンドを実行して変更を適用します。
source ~/.bashrc次のコマンドを実行して、環境変数が有効になったかどうかを確認します。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
macOS
ターミナルで次のコマンドを実行して、デフォルトのシェルタイプを表示します。
echo $SHELLデフォルトのシェルタイプに基づいて操作を実行します。
Zsh
以下のコマンドを実行して、
~/.zshrcファイルに環境変数を追加します。echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.zshrc echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.zshrc echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.zshrc次のコマンドを実行して、変更を有効にします。
source ~/.zshrc次のコマンドを実行して、環境変数が有効になったかどうかを確認します。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
Bash
次のコマンドを実行して、環境変数を
~/.bash_profileファイルに追加します。echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.bash_profile echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.bash_profile echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.bash_profile次のコマンドを実行して、変更を有効にします。
source ~/.bash_profile次のコマンドを実行して、環境変数が有効になったかどうかを確認します。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
Windows
コマンドプロンプトで次のコマンドを実行します。
setx OSS_ACCESS_KEY_ID "your-access-key-id" setx OSS_ACCESS_KEY_SECRET "your-access-key-secret" setx OSS_STS_ROLE_ARN "your-role-arn"新しいコマンドプロンプトウィンドウを開きます。
次のコマンドを実行して、新しいウィンドウで環境変数が有効になったかどうかを確認します。
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET% echo %OSS_STS_ROLE_ARN%
次のコードを参照して、サーバーで POST 署名バージョン 4 (推奨) を計算できます。ポリシーフォームフィールドの詳細については、「ポリシーフォームフィールド」をご参照ください。
Java
Maven プロジェクトに次の依存関係を追加します。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>sts20150401</artifactId>
<version>1.1.6</version>
</dependency>次のサンプルコードは、STS から一時的なアクセス認証情報を取得し、オブジェクトのアップロードに使用できる署名を計算し、アップロードコールバックを設定する方法の例を示しています。
package com.aliyun.oss.web;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Controller
public class WebController {
// OSS バケット情報。実際の情報に置き換えてください。
String bucket = "examplebucket";
String region = "cn-hangzhou";
String host = "http://examplebucket.oss-cn-hangzhou.aliyuncs.com";
// アップロードコールバックリクエストが送信されるアプリケーションサーバーの URL を指定します。URL はパブリックドメイン名である必要があります。この URL は、アプリケーションサーバーと OSS 間の通信に使用されます。オブジェクトをアップロードした後、OSS はこの URL を使用してアップロード情報をアプリケーションサーバーに送信します。
String callbackUrl = "http://oss-demo.aliyuncs.com:23450/callback"; // コールバックリクエストを受信するコールバックサーバーのアドレスを指定します。例:http://oss-demo.aliyuncs.com:23450/callback。
// OSS にアップロードされるオブジェクト名のプレフィックス。
String upload_dir = "dir";
// 一時的な認証情報の有効期間。単位:秒。
Long expire_time = 3600L;
/**
* 有効期限は、指定された有効期間に基づいて計算されます。単位:秒。
* @param seconds: 有効期間(秒)。
* @return: ISO 8601 標準の時刻文字列。例:2014-12-01T12:00:00.000Z。
*/
public static String generateExpiration(long seconds) {
// 現在のタイムスタンプ。単位:秒。
long now = Instant.now().getEpochSecond();
// 有効期限のタイムスタンプ。
long expirationTime = now + seconds;
// タイムスタンプを Instant オブジェクトに変換し、ISO 8601 形式でフォーマットします。
Instant instant = Instant.ofEpochSecond(expirationTime);
// タイムゾーンを UTC として定義します。
ZoneId zone = ZoneOffset.UTC;
// Instant オブジェクトを ZonedDateTime オブジェクトに変換します。
ZonedDateTime zonedDateTime = instant.atZone(zone);
// 日時形式を定義します。例:2023-12-03T13:00:00.000Z。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
// 日付と時刻をフォーマットします。
String formattedDate = zonedDateTime.format(formatter);
// 結果を出力します。
return formattedDate;
}
// STS クライアントを初期化します。
public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
// プロジェクトコードが漏洩すると、AccessKey ペアが漏洩し、Alibaba Cloud アカウントに属するすべてのリソースでセキュリティ問題が発生する可能性があります。
// より安全な STS を使用することを推奨します。
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必須。OSS_ACCESS_KEY_ID 環境変数が設定されていることを確認してください。
.setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID"))
// 必須。OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
.setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET"));
// エンドポイントを指定します。詳細については、https://api.aliyun.com/product/Sts をご参照ください。
config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
return new com.aliyun.sts20150401.Client(config);
}
// STS からセキュリティトークンを取得します。
public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception {
com.aliyun.sts20150401.Client client = WebController.createStsClient();
com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
// OSS_STS_ROLE_ARN 環境変数が設定されていることを確認してください。
.setRoleArn(System.getenv("OSS_STS_ROLE_ARN"))
.setRoleSessionName("yourRoleSessionName");// カスタムセッション名を指定します。
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 必要に応じて、API 操作のレスポンスを表示する独自のコードを記述します。
AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
// 後続の操作に必要な AccessKey ID、AccessKey Secret、および STS トークンは credentials に含まれています。
return response.body.credentials;
} catch (TeaException error) {
// 実際のビジネスシナリオでは例外を慎重に処理し、プロジェクトで例外を無視しないでください。この例では、例外は参照用にのみ提供されています。
// エラーメッセージを出力します。
System.out.println(error.getMessage());
// トラブルシューティング用の URL。
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
// null を返さないように、デフォルトのエラーレスポンスオブジェクトを返します。
AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials defaultCredentials = new AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials();
defaultCredentials.accessKeyId = "ERROR_ACCESS_KEY_ID";
defaultCredentials.accessKeySecret = "ERROR_ACCESS_KEY_SECRET";
defaultCredentials.securityToken = "ERROR_SECURITY_TOKEN";
return defaultCredentials;
}
@GetMapping("/get_post_signature_for_oss_upload")
public ResponseEntity<Map<String, String>> getPostSignatureForOssUpload() throws Exception {
AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials sts_data = getCredential();
String accesskeyid = sts_data.accessKeyId;
String accesskeysecret = sts_data.accessKeySecret;
String securitytoken = sts_data.securityToken;
// x-oss-credential ヘッダーで現在の日付を取得します。値は yyyyMMdd 形式です。
ZonedDateTime today = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String date = today.format(formatter);
// x-oss-date ヘッダーを取得します。
ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
String x_oss_date = now.format(formatter2);
// ステップ 1:ポリシーを作成します。
String x_oss_credential = accesskeyid + "/" + date + "/" + region + "/oss/aliyun_v4_request";
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> policy = new HashMap<>();
policy.put("expiration", generateExpiration(expire_time));
List<Object> conditions = new ArrayList<>();
Map<String, String> bucketCondition = new HashMap<>();
bucketCondition.put("bucket", bucket);
conditions.add(bucketCondition);
Map<String, String> securityTokenCondition = new HashMap<>();
securityTokenCondition.put("x-oss-security-token", securitytoken);
conditions.add(securityTokenCondition);
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", x_oss_credential); // 値を AccessKey ID に置き換えます。
conditions.add(credentialCondition);
Map<String, String> dateCondition = new HashMap<>();
dateCondition.put("x-oss-date", x_oss_date);
conditions.add(dateCondition);
conditions.add(Arrays.asList("content-length-range", 1, 10240000));
conditions.add(Arrays.asList("eq", "$success_action_status", "200"));
conditions.add(Arrays.asList("starts-with", "$key", upload_dir));
policy.put("conditions", conditions);
String jsonPolicy = mapper.writeValueAsString(policy);
// ステップ 2:署名する文字列を作成します。
String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
// ステップ 3:署名キーを計算します。
byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), date);
byte[] dateRegionKey = hmacsha256(dateKey, region);
byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
// ステップ 4:署名を計算します。
byte[] result = hmacsha256(signingKey, stringToSign);
String signature = BinaryUtil.toHex(result);
// ステップ 5:コールバックを設定します。
JSONObject jasonCallback = new JSONObject();
jasonCallback.put("callbackUrl", callbackUrl);
jasonCallback.put("callbackBody","filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
Map<String, String> response = new HashMap<>();
// Map オブジェクトにデータを追加します。
response.put("version", "OSS4-HMAC-SHA256");
response.put("policy", stringToSign);
response.put("x_oss_credential", x_oss_credential);
response.put("x_oss_date", x_oss_date);
response.put("signature", signature);
response.put("security_token", securitytoken);
response.put("dir", upload_dir);
response.put("host", host);
response.put("callback", base64CallbackBody);
// 200 OK ステータスコードを含む ResponseEntity クラスを Web クライアントに返します。その後、クライアントは PostObject 操作を実行できます。
return ResponseEntity.ok(response);
}
public static byte[] hmacsha256(byte[] key, String data) {
try {
// HMAC キー仕様を初期化し、アルゴリズムを HMAC-SHA256 に設定し、提供されたキーを使用します。
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
// Mac インスタンスを取得し、getInstance メソッドを使用してアルゴリズムを HMAC-SHA256 に設定します。
Mac mac = Mac.getInstance("HmacSHA256");
// キーを使用して Mac インスタンスを初期化します。
mac.init(secretKeySpec);
// HMAC 値を計算します。doFinal メソッドを使用して計算するデータを受け取り、計算結果を配列で返します。
byte[] hmacBytes = mac.doFinal(data.getBytes());
return hmacBytes;
} catch (Exception e) {
throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
}
}
}Python
次のコマンドを実行して依存関係をインストールします。
pip install flask
pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials次のサンプルコードは、STS から一時的なアクセス認証情報を取得し、オブジェクトのアップロードに使用できる署名を計算し、アップロードコールバックを設定する方法の例を示しています。
from flask import Flask, render_template, jsonify, request
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
import os
import json
import base64
import hmac
import datetime
import time
import hashlib
import oss2
app = Flask(__name__)
# OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET、OSS_STS_ROLE_ARN 環境変数を設定します。
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 = 'yourRoleSessionName'
# 実際のバケット名、リージョン ID、ホストエンドポイントに値を置き換えます。
bucket = 'examplebucket'
region_id = 'cn-hangzhou'
host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'
# 一時的なアクセス認証情報の有効期間を指定します。単位:秒。
expire_time = 3600
# OSS 内のオブジェクト名のプレフィックスを指定します。
upload_dir = 'dir'
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("/")
def hello_world():
return render_template('index.html')
@app.route('/get_post_signature_for_oss_upload', methods=['GET'])
def generate_upload_params():
# 設定を初期化します。
config = Config(
region_id=region_id,
access_key_id=access_key_id,
access_key_secret=access_key_secret
)
# STSClient インスタンスを作成し、一時的なアクセス認証情報を取得します。
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 から返された一時的なアクセス認証情報を使用します。
temp_access_key_id = token_data['AccessKeyId']
temp_access_key_secret = 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')
# コールバックパラメーターを Base64 でエンコードする関数を定義します。
def encode_callback(callback_params):
cb_str = json.dumps(callback_params).strip()
return oss2.compat.to_string(base64.b64encode(oss2.compat.to_bytes(cb_str)))
# コールバック設定を作成し、Base64 でエンコードします。
callback_config = {
"callbackUrl": "http://oss-demo.aliyuncs.com:23450/callback", # ローカルコールバックサーバーのアドレスを指定します。
"callbackBody": "bucket=${bucket}&object=${object}&etag=${etag}&size=${size}",
"callbackBodyType": "application/x-www-form-urlencoded"
}
encoded_callback = encode_callback(callback_config)
# ポリシーを作成し、署名を生成します。
policy = {
"expiration": expiration_time,
"conditions": [
["eq", "$success_action_status", "200"],
{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
{"x-oss-credential": f"{temp_access_key_id}/{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 = base64.b64encode(policy_str.encode()).decode()
# ステップ 3:署名キーを計算します。
dateKey = hmacsha256(("aliyun_v4" + temp_access_key_secret).encode(), dt_obj_2)
dateRegionKey = hmacsha256(dateKey, "cn-hangzhou")
dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
# ステップ 4:署名を計算します。
result = hmacsha256(signingKey, stringToSign)
signature = result.hex()
# レスポンスデータ。
response_data = {
'policy': stringToSign, # フォームフィールド。
'x_oss_signature_version': "OSS4-HMAC-SHA256", # 署名バージョンと署名計算に使用されるアルゴリズム。値を OSS4-HMAC-SHA256 に設定します。
'x_oss_credential': f"{temp_access_key_id}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request", # 派生キーに関する情報を指定するためのパラメーターセット。
'x_oss_date': dt_obj_1, # リクエスト時刻。
'signature': signature, # 署名の説明。
'host': host,
'dir': upload_dir,
'security_token': security_token, # セキュリティトークン。
'callback': encoded_callback # Base64 エンコードされたコールバック設定を返します。
}
return jsonify(response_data)
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000) # 0.0.0.0 などの他のアドレスでリッスンする必要がある場合は、サーバーに認証メカニズムを追加する必要があります。Node.js
次のコマンドを実行して依存関係をインストールします。
npm install ali-oss
npm install @alicloud/credentials
npm install express次のサンプルコードは、STS から一時的なアクセス認証情報を取得し、オブジェクトのアップロードに使用できる署名を計算し、アップロードコールバックを設定する方法の例を示しています。
const express = require('express');
const OSS = require('ali-oss');
const { STS } = require('ali-oss');
const { getCredential } = require('ali-oss/lib/common/signUtils');
const { getStandardRegion } = require('ali-oss/lib/common/utils/getStandardRegion');
const { policy2Str } = require('ali-oss/lib/common/utils/policy2Str');
const app = express();
const PORT = process.env.PORT || 8000; // ポート番号を指定します。
// 静的ファイルが保存されているディレクトリを指定します。
app.use(express.static('templates'));
const GenerateSignature = async () => {
// STS クライアントインスタンスを初期化します。
let sts = new STS({
accessKeyId: process.env.OSS_ACCESS_KEY_ID, // 環境変数から RAM ユーザーの AccessKey ID を取得します。
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET // 環境変数から RAM ユーザーの AccessKey Secret を取得します。
});
// assumeRole 操作を呼び出して STS トークンを取得します。
const result = await sts.assumeRole(process.env.env.OSS_STS_ROLE_ARN, '', '3600', 'yourRoleSessionName'); // 環境変数から RAM ロールの ARN を取得し、一時的なアクセス認証情報の有効期間を 3600 秒に設定し、ロールセッション名を yourRoleSessionName に設定します。
// 一時的なアクセス認証情報から AccessKeyId、AccessKeySecret、SecurityToken パラメーターの値を抽出します。
const accessKeyId = result.credentials.AccessKeyId;
const accessKeySecret = result.credentials.AccessKeySecret;
const securityToken = result.credentials.SecurityToken;
// OSS クライアントインスタンスを初期化します。
const client = new OSS({
bucket: 'examplebucket', // examplebucket を実際のバケット名に置き換えます。
region: 'cn-hangzhou', // cn-hangzhou をバケットが配置されているリージョンに置き換えます。
accessKeyId,
accessKeySecret,
stsToken: securityToken,
refreshSTSTokenInterval: 0,
refreshSTSToken: async () => {
const { accessKeyId, accessKeySecret, securityToken } = await client.getCredential();
return { accessKeyId, accessKeySecret, stsToken: securityToken };
},
});
// フォームフィールドを格納する Map を作成します。
const formData = new Map();
// 署名の有効期限を現在時刻から 10 分後に設定します。
const date = new Date();
const expirationDate = new Date(date);
expirationDate.setMinutes(date.getMinutes() + 10);
// 日付を ISO 8601 標準に準拠した UTC 時刻文字列にフォーマットします。
function padTo2Digits(num) {
return num.toString().padStart(2, '0');
}
function formatDateToUTC(date) {
return (
date.getUTCFullYear() +
padTo2Digits(date.getUTCMonth() + 1) +
padTo2Digits(date.getUTCDate()) +
'T' +
padTo2Digits(date.getUTCHours()) +
padTo2Digits(date.getUTCMinutes()) +
padTo2Digits(date.getUTCSeconds()) +
'Z'
);
}
const formattedDate = formatDateToUTC(expirationDate);
// アップロードコールバックリクエストが送信されるアプリケーションサーバーの URL を指定します。URL はパブリックドメイン名である必要があります。この URL は、アプリケーションサーバーと OSS 間の通信に使用されます。オブジェクトをアップロードした後、OSS はこの URL を使用してアップロードされたオブジェクトに関する情報をアプリケーションサーバーに送信します。たとえば、callbackUrl を https://oss-demo.aliyuncs.com:23450 に設定できます。
// x-oss-credential を生成し、フォームデータを指定します。
const credential = getCredential(formattedDate.split('T')[0], getStandardRegion(client.options.region), client.options.accessKeyId);
formData.set('x_oss_date', formattedDate);
formData.set('x_oss_credential', credential);
formData.set('x_oss_signature_version', 'OSS4-HMAC-SHA256');
// ポリシーを作成します。
// 次のポリシーフォームフィールドでは、必須フィールドのみが指定されています。
const policy = {
expiration: expirationDate.toISOString(),
conditions: [
{ 'bucket': 'examplebucket' }, // examplebucket を実際のバケット名に置き換えます。
{ 'x-oss-credential': credential },
{ 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
{ 'x-oss-date': formattedDate },
],
};
// セキュリティトークンが存在する場合は、ポリシーとフォームデータに追加します。
if (client.options.stsToken) {
policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
formData.set('security_token', client.options.stsToken);
}
// 署名を生成し、フォームデータを指定します。
const signature = client.signPostObjectPolicyV4(policy, date);
formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
formData.set('signature', signature);
const callback = {
callbackUrl: 'http://oss-demo.aliyuncs.com:23450/callback',// コールバックリクエストを受信するコールバックサーバーのアドレスを指定します。例:http://oss-demo.aliyuncs.com:23450/callback。
callbackBody:// コールバックリクエストに含めたいコンテンツ(アップロードされたオブジェクトの ETag や mimeType など)を指定します。
"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
callbackBodyType: "application/x-www-form-urlencoded",// コールバックのコンテンツタイプを指定します。
};
// フォームデータを返します。
return {
host: `http://${client.options.bucket}.oss-${client.options.region}.aliyuncs.com`,
policy: Buffer.from(policy2Str(policy), 'utf8').toString('base64'),
x_oss_signature_version: 'OSS4-HMAC-SHA256',
x_oss_credential: credential,
x_oss_date: formattedDate,
signature: signature,
dir: 'user-dir', // OSS にアップロードしたいオブジェクトの名前に含まれるプレフィックスを指定します。
callback: Buffer.from(JSON.stringify(callback)).toString("base64"),// Buffer.from を使用した Base64 エンコードされた JSON。
security_token: client.options.stsToken
};
};
app.get('/get_post_signature_for_oss_upload', async (req, res) => {
try {
const result = await GenerateSignature();
res.json(result); // 生成された署名データを返します。
} catch (error) {
console.error('Error generating signature:', error);
res.status(500).send('Error generating signature');
}
});
app.listen(PORT, () => {
console.log(`Server is running on http://127.0.0.1:${PORT}`); //0.0.0.0 などの他のアドレスでリッスンする必要がある場合は、サーバーに認証メカニズムを追加する必要があります。
});Go
次のコマンドを実行して依存関係をインストールします。
go get -u github.com/aliyun/credentials-go
go mod tidy次のサンプルコードは、STS から一時的なアクセス認証情報を取得し、オブジェクトのアップロードに使用できる署名を計算し、アップロードコールバックを設定する方法の例を示しています。
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"hash"
"log"
"net/http"
"os"
"time"
"github.com/aliyun/credentials-go/credentials"
)
// グローバル変数を定義します。
var (
region string
bucketName string
product = "oss"
)
// PolicyToken 構造体を使用して、生成されたフォームデータを格納します。
type PolicyToken struct {
Policy string `json:"policy"`
SecurityToken string `json:"security_token"`
SignatureVersion string `json:"x_oss_signature_version"`
Credential string `json:"x_oss_credential"`
Date string `json:"x_oss_date"`
Signature string `json:"signature"`
Host string `json:"host"`
Dir string `json:"dir"`
Callback string `json:"callback"`
}
type CallbackParam struct{
CallbackUrl string `json:"callbackUrl"`
CallbackBody string `json:"callbackBody"`
CallbackBodyType string `json:"callbackBodyType"`
}
func main() {
// デフォルトの IP とポート文字列を指定します。
strIPPort := ":8080"
if len(os.Args) == 3 {
strIPPort = fmt.Sprintf("%s:%s", os.Args[1], os.Args[2])
} else if len(os.Args) != 1 {
fmt.Println("Usage : go run test1.go ")
fmt.Println("Usage : go run test1.go ip port ")
fmt.Println("Example : go run test1.go 11.22.**.** 80 ")
fmt.Println("Example : go run test1.go 0.0.0.0 8080 ")
fmt.Println("")
os.Exit(0)
}
// サーバーの IP アドレスとポートを表示します。
fmt.Printf("server is running on %s \n", strIPPort)
// ルートパスリクエストを処理する関数を登録します。
http.HandleFunc("/", handlerRequest)
// 署名を取得するために開始されたリクエストを処理する関数を登録します。
http.HandleFunc("/get_post_signature_for_oss_upload", handleGetPostSignature)
// HTTP サーバーを開始します。
err := http.ListenAndServe(strIPPort, nil)
if err != nil {
strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
panic(strError)
}
}
// handlerRequest 関数を使用して、ルートパスリクエストを処理します。
func handlerRequest(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
http.ServeFile(w, r, "templates/index.html")
return
}
http.NotFound(w, r)
}
// handleGetPostSignature 関数を使用して、署名を取得するために開始されたリクエストを処理します。
func handleGetPostSignature(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
response := getPolicyToken()
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*") // クロスオリジンリクエストを許可します。
w.Write([]byte(response))
return
}
http.NotFound(w, r)
}
// getPolicyToken 関数を使用して、オブジェクトのアップロードに必要な署名とアクセス認証情報を生成します。
func getPolicyToken() string {
// バケットが配置されているリージョンを指定します。
region = "cn-hangzhou"
// バケット名を指定します。
bucketName = "examplebucket"
// データがアップロードされる URL を指定します。https://%s.oss-%s.aliyuncs.com", bucketName, region)
// オブジェクトをアップロードするディレクトリを指定します。
dir := "user-dir"
// アップロードコールバックリクエストが送信されるアプリケーションサーバーの URL を指定します。IP アドレスとポート番号を実際の値に置き換えます。
callbackUrl := "http://oss-demo.aliyuncs.com:23450/callback";
config := new(credentials.Config).
SetType("ram_role_arn").
SetAccessKeyId(os.Getenv("OSS_ACCESS_KEY_ID")).
SetAccessKeySecret(os.Getenv("OSS_ACCESS_KEY_SECRET")).
SetRoleArn(os.Getenv("OSS_STS_ROLE_ARN")).
SetRoleSessionName("Role_Session_Name").
SetPolicy("").
SetRoleSessionExpiration(3600)
// 設定に基づいて認証情報プロバイダーを作成します。
provider, err := credentials.NewCredential(config)
if err != nil {
log.Fatalf("NewCredential fail, err:%v", err)
}
// 認証情報プロバイダーからアクセス認証情報を取得します。
cred, err := provider.GetCredential()
if err != nil {
log.Fatalf("GetCredential fail, err:%v", err)
}
// ポリシーを作成します。
utcTime := time.Now().UTC()
date := utcTime.Format("20060102")
expiration := utcTime.Add(1 * time.Hour)
policyMap := map[string]any{
"expiration": expiration.Format("2006-01-02T15:04:05.000Z"),
"conditions": []any{
map[string]string{"bucket": bucketName},
map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
map[string]string{"x-oss-credential": fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request", *cred.AccessKeyId, date, region, product)},
map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
map[string]string{"x-oss-security-token": *cred.SecurityToken},
},
}
// ポリシーの形式を JSON に変換します。
policy, err := json.Marshal(policyMap)
if err != nil {
log.Fatalf("json.Marshal fail, err:%v", err)
}
// 署名する文字列を作成します。
stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
hmacHash := func() hash.Hash { return sha256.New() }
// 署名キーを作成します。
signingKey := "aliyun_v4" + *cred.AccessKeySecret
h1 := hmac.New(hmacHash, []byte(signingKey))
io.WriteString(h1, date)
h1Key := h1.Sum(nil)
h2 := hmac.New(hmacHash, h1Key)
io.WriteString(h2, region)
h2Key := h2.Sum(nil)
h3 := hmac.New(hmacHash, h2Key)
io.WriteString(h3, product)
h3Key := h3.Sum(nil)
h4 := hmac.New(hmacHash, h3Key)
io.WriteString(h4, "aliyun_v4_request")
h4Key := h4.Sum(nil)
// 署名を生成します。
h := hmac.New(hmacHash, h4Key)
io.WriteString(h, stringToSign)
signature := hex.EncodeToString(h.Sum(nil))
var callbackParam CallbackParam
callbackParam.CallbackUrl = callbackUrl
callbackParam.CallbackBody = "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}"
callbackParam.CallbackBodyType = "application/x-www-form-urlencoded"
callback_str,err:=json.Marshal(callbackParam)
if err != nil {
fmt.Println("callback json err:", err)
}
callbackBase64 := base64.StdEncoding.EncodeToString(callback_str)
// フロントエンドフォームに返されるコンテンツを作成します。
policyToken := PolicyToken{
Policy: stringToSign,
SecurityToken: *cred.SecurityToken,
SignatureVersion: "OSS4-HMAC-SHA256",
Credential: fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request", *cred.AccessKeyId, date, region, product),
Date: utcTime.UTC().Format("20060102T150405Z"),
Signature: signature,
Host: host, // オブジェクトがアップロードされるバケットを返します。
Dir: dir, // データがアップロードされるディレクトリ。
Callback: callbackBase64, // アップロードコールバックパラメーターを返します。
}
response, err := json.Marshal(policyToken)
if err != nil {
fmt.Println("json err:", err)
}
return string(response)
}PHP
次のコマンドを実行して依存関係をインストールします。
composer install次のサンプルコードは、STS から一時的なアクセス認証情報を取得し、オブジェクトのアップロードに使用できる署名を計算し、アップロードコールバックを設定する方法の例を示しています。
<?php
// Alibaba Cloud SDK を使用します。
require_once __DIR__ . '/vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;
// エラー表示を無効にします。
ini_set('display_errors', '0');
$bucket = 'examplebucket'; // 実際のバケット名に値を置き換えます。
$region_id = 'cn-hangzhou'; // バケットが配置されているリージョンに値を置き換えます。
$host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'; // バケットの URL に値を置き換えます。
$expire_time = 3600; // 有効期限。単位:秒。
$upload_dir = 'user-dir'; // アップロードするオブジェクトの名前に含まれるプレフィックス。
// アップロードコールバックリクエストが送信されるアプリケーションサーバーの URL を指定します。IP アドレスとポート番号を実際の値に置き換えます。
$callbackUrl = 'http://oss-demo.aliyuncs.com:23450/callback';
// HMAC-SHA256 値を計算します。
function hmacsha256($key, $data) {
return hash_hmac('sha256', $data, $key, true);
}
// 署名を取得するために開始されたリクエストを処理します。
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/get_post_signature_for_oss_upload') {
AlibabaCloud::accessKeyClient(getenv('OSS_ACCESS_KEY_ID'), getenv('OSS_ACCESS_KEY_SECRET'))
->regionId('cn-hangzhou')
->asDefaultClient();
// STS から一時的なアクセス認証情報を取得するためのリクエストを作成します。
$request = Sts::v20150401()->assumeRole();
// STS リクエストを開始し、結果を取得します。
// <YOUR_ROLE_SESSION_NAME> をカスタムセッション名(例:oss-role-session)に置き換えます。
// <YOUR_ROLE_ARN> を、指定されたバケットにオブジェクトをアップロードする権限を持つ RAM ロールの ARN に置き換えます。
$result = $request
->withRoleSessionName('oss-role-session')
->withDurationSeconds(3600)
->withRoleArn(getenv('OSS_STS_ROLE_ARN')) // OSS_STS_ROLE_ARN を RAM ロールの ARN に置き換えます。
->request();
// STS リクエストへのレスポンスで認証情報を取得します。
$tokenData = $result->get('Credentials');
// 返された結果から JSON データを構築します。
$tempAccessKeyId = $tokenData['AccessKeyId'];
$tempAccessKeySecret = $tokenData['AccessKeySecret'];
$securityToken = $tokenData['SecurityToken'];
$now = time();
$dtObj = gmdate('Ymd\THis\Z', $now);
$dtObj1 = gmdate('Ymd', $now);
$dtObjPlus3h = gmdate('Y-m-d\TH:i:s.u\Z', strtotime('+3 hours', $now));
// ポリシーを作成します。
$policy = [
"expiration" => $dtObjPlus3h,
"conditions" => [
["x-oss-signature-version" => "OSS4-HMAC-SHA256"],
["x-oss-credential" => "{$tempAccessKeyId}/{$dtObj1}/cn-hangzhou/oss/aliyun_v4_request"],
["x-oss-security-token" => $securityToken],
["x-oss-date" => $dtObj],
]
];
$policyStr = json_encode($policy);
// 署名する文字列を作成します。
$stringToSign = base64_encode($policyStr);
// 署名キーを計算します。
$dateKey = hmacsha256(('aliyun_v4' . $tempAccessKeySecret), $dtObj1);
$dateRegionKey = hmacsha256($dateKey, 'cn-hangzhou');
$dateRegionServiceKey = hmacsha256($dateRegionKey, 'oss');
$signingKey = hmacsha256($dateRegionServiceKey, 'aliyun_v4_request');
// 署名を計算します。
$result = hmacsha256($signingKey, $stringToSign);
$signature = bin2hex($result);
$callback_param = array(
'callbackUrl' => $callbackUrl,
'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
'callbackBodyType' => "application/x-www-form-urlencoded"
);
$callback_string = json_encode($callback_param);
$base64_callback_body = base64_encode($callback_string);
// 署名データを返します。
$responseData = [
'policy' => $stringToSign,
'x_oss_signature_version' => "OSS4-HMAC-SHA256",
'x_oss_credential' => "{$tempAccessKeyId}/{$dtObj1}/cn-hangzhou/oss/aliyun_v4_request",
'x_oss_date' => $dtObj,
'signature' => $signature,
'host' => $host,
'dir' => $upload_dir,
'security_token' => $securityToken,
'callback' => $base64_callback_body,
];
header('Content-Type: application/json');
echo json_encode($responseData);
exit;
}
// ホームページルートを指定します。
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/') {
echo file_get_contents(__DIR__ . '/public/index.html');
exit;
}
// 他のルートを指定します。
http_response_code(404);
echo json_encode(['message' => 'Not Found']);
exit;
?>Callback パラメーターは、JSON 形式で複数のフィールドを含む Base64 エンコードされた文字列です。コールバックパラメーターを構築するには、コールバックリクエストが送信されるサーバーの URL (callbackUrl) とコールバックリクエストのコンテンツ (callbackBody) を指定する必要があります。
{"callbackUrl":"http://oss-demo.aliyuncs.com:23450/callback",
"callbackBody":"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
"callbackBodyType":"application/x-www-form-urlencoded"}パラメーター | 説明 |
callbackUrl | OSS がリクエストを送信するアプリケーションサーバーの URL。 |
callbackBody | OSS がアプリケーションサーバーに送信するコンテンツ。画像以外のオブジェクトをアップロードする場合、コンテンツはオブジェクト名、サイズ、タイプになります。画像をアップロードする場合、画像の高さと幅を指定できます。 |
callbackBodyType | リクエストのコンテンツタイプ。 有効な値:
|
上記の例は、コールバックの設定方法のみを示しています。要件に基づいてサーバーコードを変更してコールバックを設定できます。詳細については、「コールバック」をご参照ください。
ステップ 3:Web クライアントの設定
Web クライアントでのフォームアップロードリクエストの構築と送信
Web クライアントがアプリケーションサーバーから必要な情報を受信した後、その情報を使用して HTML フォームを作成するリクエストを構築できます。リクエストはファイルアップロードのために直接 OSS に送信されます。
Web クライアントが受信するレスポンスの例
次の情報は、アプリケーションサーバーから Web クライアントに返されます。
{
"dir": "user-dirs",
"host": "http://examplebucket.oss-cn-hangzhou.aliyuncs.com",
"policy": "eyJl****",
"security_token": "CAIS****",
"signature": "9103****",
"x_oss_credential": "STS.NSpW****/20241127/cn-hangzhou/oss/aliyun_v4_request",
"x_oss_date": "20241127T060941Z",
"x_oss_signature_version": "OSS4-HMAC-SHA256",
"callback":"eyJjYWxsYmFja1VybCI6Imh0dHA6Ly9vc3MtZGVtby5hbGl5dW5jcy5jb206MjM0NTAiLAoiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JHtvYmplY3R9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZoZWlnaHQ9JHtpbWFnZUluZm8uaGVpZ2h0fSZ3aWR0aD0ke2ltYWdlSW5mby53aWR0aH0iLAoiY2FsbGJhY2tCb2R5VHlwZSI6ImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCJ9"
}次の表は、本文に含まれるフィールドについて説明しています。
フィールド | 説明 |
dir | アップロードできるファイルのプレフィックスを制限します。 |
host | バケットのドメイン名。 |
policy | フォームアップロードのポリシー。詳細については、「Post Policy」をご参照ください。 |
security_token | STS から取得したセキュリティトークン。 |
signature | ポリシーの署名文字列。詳細については、「Post Signature」をご参照ください。 |
x_oss_credential | 派生キーを指定するために使用されるパラメーターセット。 |
x_oss_date | ISO 8601 規格の日時フォーマットに従った、リクエストの時刻です。例: |
x_oss_signature_version | 署名バージョンと署名の計算に使用されるアルゴリズム。値を OSS4-HMAC-SHA256 に設定します。 |
callback | コールバックのコンテンツ。 |
フォームリクエストには、ファイルコンテンツとサーバーから返されたパラメーターが含まれます。
Web クライアントは、フォームリクエストを使用して OSS と直接通信し、ファイルをアップロードできます。
ファイルフォームフィールドを除き、キーを含む他のすべてのフォームフィールドのサイズは 8 KB を超えることはできません。
デフォルトでは、アップロードしたいオブジェクトと同じ名前の既存のオブジェクトは上書きされます。既存のオブジェクトを上書きしたくない場合は、アップロードリクエストに x-oss-forbid-overwrite ヘッダーを含め、x-oss-forbid-overwrite ヘッダーを true に設定します。これにより、既存のオブジェクトと同じ名前のオブジェクトをアップロードすると、アップロードは失敗し、OSS は FileAlreadyExists エラーコードを返します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>サーバーで署名を生成して OSS にファイルをアップロード</title>
</head>
<body>
<div class="container">
<form>
<div class="mb-3">
<label for="file" class="form-label">ファイルを選択:</label>
<input type="file" class="form-control" id="file" name="file" required />
</div>
<button type="submit" class="btn btn-primary">アップロード</button>
</form>
<div id="callback-info" class="mt-3" style="display: none;">
<h4>コールバック情報:</h4>
<pre id="callback-content"></pre>
</div>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
const form = document.querySelector("form");
const fileInput = document.querySelector("#file");
const callbackInfo = document.querySelector("#callback-info");
const callbackContent = document.querySelector("#callback-content");
form.addEventListener("submit", (event) => {
event.preventDefault();
const file = fileInput.files[0];
if (!file) {
alert('アップロードするファイルを選択してください。');
return;
}
const filename = file.name;
fetch("/get_post_signature_for_oss_upload", { method: "GET" })
.then((response) => {
if (!response.ok) {
throw new Error("署名の取得に失敗しました");
}
return response.json();
})
.then((data) => {
let formData = new FormData();
formData.append("success_action_status", "200");
formData.append("policy", data.policy);
formData.append("x-oss-signature", data.signature);
formData.append("x-oss-signature-version", "OSS4-HMAC-SHA256");
formData.append("x-oss-credential", data.x_oss_credential);
formData.append("x-oss-date", data.x_oss_date);
formData.append("key", data.dir + file.name); // ファイル名。
formData.append("x-oss-security-token", data.security_token);
formData.append("callback", data.callback); // コールバックパラメーターを指定します。
formData.append("file", file); // フォームフィールド "file" は最後にする必要があります。
return fetch(data.host, {
method: "POST",
body: formData
});
})
.then((response) => {
if (response.ok) {
console.log("アップロード済み");
alert("ファイルがアップロードされました");
return response.json(); // コールバック情報を解析します。
} else {
console.log("アップロードに失敗しました。次のレスポンスを確認してください:", response);
alert("オブジェクトのアップロードに失敗しました。オブジェクトを再アップロードしてください");
}
})
.then((callbackData) => {
if (callbackData) {
callbackContent.textContent = JSON.stringify(callbackData, null, 2);
callbackInfo.style.display = "block";
}
})
.catch((error) => {
console.error("エラーが発生しました:", error);
});
});
});
</script>
</body>
</html>HTML フォームには、ファイル入力フィールドと送信ボタンが含まれています。アップロードするファイルを選択してフォームを送信できます。
フォームを送信すると、JavaScript コードを使用してデフォルトのフォーム送信がブロックされ、アップロードに必要な署名情報が AJAX (Asynchronous JavaScript and XML) リクエストを使用してサーバーから取得されます。
署名情報を取得後、すべての必須フォームフィールドを含む
FormDataオブジェクトが構築されます。POST リクエストは、
fetchメソッドを使用してファイルをアップロードするために、OSS サービスの URL に送信されます。
ファイルがアップロードされると、「ファイルがアップロードされました」というメッセージが表示されます。ファイルのアップロードに失敗すると、エラーメッセージが表示されます。対応するコールバック情報がフロントエンドページに返されます。
検証
デプロイメントが完了したら、サーバーアドレスにアクセスして、Web クライアント署名アップロード機能を使用できます。
ブラウザでサーバーアドレスにアクセスし、[ファイルを選択] ボタンをクリックしてファイルを選択し、ファイルをアップロードします。次の図に例を示します。
[バケットリスト] ページで、ユーザーがアップロードしたファイルを保存するバケットを見つけ、ファイルがアップロードされているかどうかを確認します。
リソースのクリーンアップ
Web アプリケーションを構築するために、ECS インスタンス、OSS バケット、RAM ユーザー、RAM ロールを作成しました。ソリューションを検証した後、次の操作を実行してリソースを解放できます。これにより、不要な料金やセキュリティリスクを回避できます。
ECS インスタンスのリリース
作成した ECS インスタンスが不要になった場合は、リリースできます。ECS インスタンスがリリースされると、インスタンスの課金は停止し、インスタンスのデータは失われ、復元できなくなります。ECS インスタンスをリリースするには、次の手順を実行します。
ECS コンソールの [インスタンス] ページに戻り、リージョンとインスタンス ID に基づいて ECS インスタンスを見つけ、[操作]
列の をクリックします。[リリース] を選択します。

インスタンスが正しいことを確認した後、[今すぐリリース] を選択し、[次へ] をクリックします。
リリースされようとしている関連リソースを確認し、関連するデータリスクを理解してから、[OK] をクリックして ECS インスタンスをリリースします。
ECS インスタンスがリリースされると、インスタンスのシステムディスクがリリースされます。インスタンスにパブリック IP アドレスが割り当てられていた場合、その IP アドレスもリリースされます。
ECS インスタンスがリリースされても、関連するセキュリティグループ、vSwitch、VPC はリリースされません。セキュリティグループ、vSwitch、VPC には課金されません。ビジネス要件に基づいて、これらを保持またはリリースできます。
EIP が ECS インスタンスに関連付けられている場合、インスタンスがリリースされても EIP は保持されます。EIP には課金されます。ビジネス要件に基づいて、EIP を保持またはリリースできます。
バケットの削除
OSS コンソールにログインします。
バケット をクリックし、バケット名をクリックします。
バケット内のすべてのオブジェクトを削除します。
左側のナビゲーションウィンドウで、バケットの削除 をクリックし、指示に従ってバケットを削除します。
RAM ユーザーの削除
RAM 管理者として RAM コンソールにログインします。
左側のナビゲーションウィンドウで、[ID 管理] > [ユーザー] を選択します。
[ユーザー] ページで、RAM ユーザーの [操作] 列にある [削除] をクリックします。
複数の RAM ユーザーを選択し、ユーザーリストの下にある [ユーザーの削除] をクリックして、一度に複数の RAM ユーザーをゴミ箱に移動することもできます。
[ユーザーの削除] ダイアログボックスで、削除の影響を注意深く読み、RAM ユーザーの名前を入力して、[ゴミ箱に移動] をクリックします。
RAM ロールの削除
RAM 管理者として RAM コンソールにログインします。
左側のナビゲーションウィンドウで、[ID 管理] > [ロール] を選択します。
[ロール] ページで、RAM ロールの [操作] 列にある [ロールの削除] をクリックします。
[ロールの削除] ダイアログボックスで、RAM ロールの名前を入力し、[ロールの削除] をクリックします。
説明RAM ロールにポリシーがアタッチされている場合、RAM ロールを削除するとポリシーはデタッチされます。
よくある質問
一度に複数のオブジェクトを OSS にアップロードするにはどうすればよいですか?
このサービスは、一度に複数のオブジェクトを OSS にアップロードするための API 操作をサポートしていません。一度に複数のオブジェクトをアップロードしたい場合は、単一のオブジェクトをアップロードする手順を繰り返し実行できます。
サーバーから署名情報を取得し、アップロードコールバックを設定する際に、コールバックリクエストのヘッダーを指定できますか?
いいえ、カスタムコールバックパラメーター、つまりコールバックリクエストの本文は指定できません。ただし、コールバック URL への OSS コールバックリクエストに含まれるヘッダーも指定できません。