PostObject 操作を使用すると、Web クライアントから Object Storage Service (OSS) へ直接ファイルをアップロードできます。この操作は、セキュリティのためにサーバーで生成された署名を使用し、ビジネス要件に基づいてアップロードを制限するポリシーを設定することもできます。
ソリューション概要
サーバーサイド署名を使用した直接アップロードを実装するには、次の 3 つの手順に従ってください。
一時的アクセス認証情報を使用することで、サーバーの長期キーが公開されるのを防ぎ、ファイルアップロードのセキュリティを強化できます。
-
OSS の設定: コンソールで、ユーザーファイルを保存するためのバケットを作成します。次に、Web クライアントからのクロスオリジンリクエストを許可するために、バケットのクロスオリジンリソース共有 (CORS) ルールを設定します。
-
サーバーの設定: Security Token Service (STS) を呼び出し、一時的アクセス認証情報を取得します。次に、この認証情報とサーバーサイドのアップロードポリシーを使い、署名を生成します。このポリシーには、バケット名、ディレクトリパス、有効期限などのパラメータが含まれます。この署名により、ユーザーは指定された期間内にファイルをアップロードできるようになります。
-
Web クライアントの設定: HTML フォームリクエストを構築し、署名を用いてファイルを OSS へアップロードします。
サンプルプロジェクト
-
Java のサンプルプロジェクトは、server-signed-direct-upload-java.zip をご参照ください。
-
Python のサンプルプロジェクトは、server-signed-direct-upload-python.zip をご参照ください。
-
Node.js のサンプルプロジェクトは、server-signed-direct-upload-nodejs.zip をご参照ください。
-
Go のサンプルプロジェクトは、server-signed-direct-upload-go.zip をご参照ください。
-
PHP のサンプルプロジェクトは、server-signed-direct-upload-php.zip をご参照ください。
手順
ステップ 1: OSS の設定
バケットの作成
Web ブラウザーから直接アップロードされるファイルを保存するために、OSS バケットを作成します。
-
OSS コンソールにログインします。
-
左側メニューで バケット、バケットの作成 の順にクリックします。
-
バケットの作成 パネルで、[クイック作成] を選択し、次のパラメーターを設定します。
パラメーター
サンプル値
[バケット名]
web-direct-upload
[リージョン]
China (Hangzhou)
-
OK をクリックします。
CORS ルールの設定
OSS バケットに CORS ルールを設定します。
-
[バケット] ページで、対象のバケットをクリックします。
-
[クロスオリジンリソース共有の設定] ページで、ルールの作成 をクリックします。
-
ルールの作成 パネルで、次のパラメーターを設定します。
パラメーター
サンプル値
[ソース]
*
[許可されたメソッド]
POST、PUT、GET
[許可されたヘッダー]
*
-
OK をクリックします。
ステップ 2:サーバーの設定
本番デプロイですでにサーバーがある場合は、準備をスキップして 1. ユーザー権限の設定 に直接進んでください。
ECS インスタンスの作成
ステップ 1:ECS インスタンスの作成
[カスタム起動] ページに移動し、Elastic Compute Service (ECS) インスタンスの作成に必要な基本リソースを選択します。
-
リージョンと課金方法の選択
-
ビジネス要件に基づいて課金方法を選択します。このチュートリアルでは、柔軟性の高い 従量課金 モードを使用します。
-
一般的に、ユーザーに近いリージョンを選択すると、ネットワークレイテンシーが低減され、アクセスが高速になります。このチュートリアルでは、例として China (Hangzhou) を使用します。
[課金方法] で、従量課金 (後払いおよびオンデマンド) を選択します。従量課金のインスタンスは ICP 登録をサポートしていません。インスタンスの作成後、そのリージョンは変更できません。異なるリージョンのインスタンスは、内部ネットワーク経由で通信できません。
-
-
Virtual Private Cloud (VPC) と vSwitch の作成
Virtual Private Cloud (VPC) を作成する際は、ECS インスタンスと同じリージョンを選択し、ビジネス要件に基づいて CIDR ブロックを計画します。このチュートリアルでは、例として China (Hangzhou) リージョンでの VPC と vSwitch の作成を取り上げます。VPC と vSwitch を作成した後、ECS の購入ページに戻り、ページを更新してそれらを選択します。
説明VPC を作成する際に vSwitch を作成できます。

[VPC の作成] ページで、[名前] を ProjectA-VPC に設定し、[IPv4 CIDR ブロック] で [IPv4 CIDR ブロックを手動で指定] を選択して
192.168.0.0/16を入力し、[IPv6 CIDR ブロック] で [割り当てない] を選択します。vSwitch の設定例:[名前] を ProjectA-vSwitch に設定し、[ゾーン] で [杭州ゾーン H] を選択し、[IPv4 CIDR ブロック] を
192.168.10.0/24に設定してから、[OK] をクリックします。
-
インスタンスタイプとイメージの選択
インスタンスタイプとイメージを選択します。イメージは、インスタンスにインストールされるオペレーティングシステムとバージョンを決定します。このチュートリアルでは、費用対効果が高く、テスト要件を満たす
ecs.e-c1m1.largeインスタンスタイプを使用します。イメージはAlibaba Cloud Linux 3.2104 LTS 64-bitパブリックイメージです。
-
ストレージの設定
このチュートリアルのシンプルな Web システムでは、オペレーティングシステム用にシステムディスクがあれば十分なため、データディスクは不要です。
システムディスクには ESSD を選択し、[パフォーマンスレベル] を PL0 に、[容量] を 40 GiB に設定し、[インスタンスに連動してリリース] を選択して、データディスクは追加しません。
-
パブリック IP アドレスの割り当て
簡単にするため、このチュートリアルではインスタンスに直接パブリック IP アドレスを割り当てます。または、インスタンスの作成後に Elastic IP Address (EIP) を関連付けることもできます。詳細については、「クラウド リソースとの EIP の関連付け」をご参照ください。
説明-
パブリック IP アドレスが割り当てられていない場合、インターネットから SSH を使用してインスタンスに直接アクセスしたり、インスタンス上の Web サービスのデプロイを検証したりすることはできません。
-
このチュートリアルでは、帯域幅の課金方法として トラフィック課金 を使用します。この方法では、消費したパブリックトラフィックに対してのみ課金されます。詳細については、「パブリック帯域幅の課金」をご参照ください。
[ピーク帯域幅] を 5 Mbps に設定します。
-
-
セキュリティグループの作成
インスタンス用のセキュリティグループを作成します。セキュリティグループは、ECS インスタンスのインバウンドおよびアウトバウンドトラフィックを制御する仮想ファイアウォールです。セキュリティグループを作成する際は、後で ECS インスタンスにアクセスできるように、次のポートでのトラフィックを許可します。
ポート範囲:SSH (22)、HTTP (80)、および HTTPS (443)。
説明-
[ポート範囲] で選択したポートは、ECS インスタンス上で実行されるアプリケーションに必要です。
-
デフォルトでは、ここで作成されるセキュリティグループには、送信元を 0.0.0.0/0 に設定するルールが含まれています。これにより、任意の IP アドレスから指定されたポートへのアクセスが許可されます。リクエスト元クライアントの IP アドレスがわかっている場合は、後で送信元を特定の IP 範囲に制限することを推奨します。詳細については、「セキュリティグループルールの変更」をご参照ください。
[セキュリティグループタイプ] セクションで、[基本セキュリティグループ] を選択します。
-
-
キーペアの作成
-
キーペアは、安全なログインに用いる認証情報です。キーペアを作成した後、その秘密鍵をダウンロードする必要があります。この秘密鍵は、ECS インスタンスへの接続 に必要です。その後、ECS の購入ページに戻り、ページを更新してキーペアを選択します。
-
rootユーザーは、オペレーティングシステムで最も高い権限を持っており、ログイン名としてrootを使用するとセキュリティリスクが生じる可能性があります。ログイン名としてecs-userを使用することを推奨します。説明キーペアを作成すると、秘密鍵が自動的にダウンロードされます。ブラウザのダウンロード履歴から
.pem秘密鍵ファイルを保存してください。[ログイン認証情報] セクションで、[キーペア] タブを選択し、[キーペアの作成] をクリックします。次に、[キーペア] ドロップダウンリストから、新しく作成したキーペア (例:
ecs-test) を選択します。
-
-
ECS インスタンスの作成と表示
ECS インスタンスに必要なリソースを選択したら、[注文の作成] をクリックします。成功ダイアログボックスで [マネジメントコンソール] をクリックして、新しいインスタンスを表示します。後で使用するために、次の情報を保存してください:
-
インスタンス ID:インスタンスリストでインスタンスを検索する際に使用します。
-
リージョン:インスタンスリストでインスタンスを検索する際に使用します。
-
パブリック IP アドレス:Web サービスのデプロイを検証する際に使用します。
-
ステップ 2:ECS インスタンスへの接続
-
ECS コンソール の [インスタンス] ページで、リージョンと ID を使用してインスタンスを見つけ、[操作] 列の 接続 をクリックします。
-
リモート接続 ダイアログボックスで、ワークベンチ の横にある 今すぐサインイン をクリックします。
-
[インスタンスにログオン] ダイアログボックスで、[接続方法] に [ターミナル接続]、[認証方法] に [SSH キー認証] を選択し、秘密鍵ファイルを入力またはアップロードした後、[ログオン] をクリックして
ecs-userユーザーとして接続します。 -
説明
キーペアを作成すると、秘密鍵ファイル (
.pem) がお使いのデバイスに自動的にダウンロードされます。ブラウザのダウンロード履歴でファイルをご確認ください。 -
次の出力が表示されたら、ECS インスタンスへのログオンは成功です。
Welcome to Alibaba Cloud Elastic Compute Service ! Last login: Sun Sep 29 15:35:22 2024 from xxx [ecs-user@iz*** ~]$
ユーザー権限
デプロイ後に権限不足が原因で OSS へのアップロードが失敗するのを防ぐため、RAM ユーザーを作成し、必要な権限を設定します。
ステップ 1: RAM ユーザーの作成
RAM ユーザーを作成し、その AccessKey ペアを取得して、アプリケーションサーバーの長期的な認証情報として使用します。
-
Alibaba Cloud アカウントまたは RAM 管理者として RAM コンソール にログインします。
-
左側のナビゲーションペインで、[アイデンティティ > ユーザー] を選択します。
-
[ユーザーの作成] をクリックします。
-
[ログイン名] と [表示名] を入力します。
-
アクセスモード セクションで、[プログラムによるアクセス] を選択し、[OK] をクリックします。
AccessKey Secret は作成時にのみ表示され、後から取得することはできません。安全な場所に保管してください。
-
[操作] 列で [コピー] をクリックし、AccessKey ペア (AccessKey ID と AccessKey シークレット) を保存します。
ステップ 2: AssumeRole 権限の付与
RAM ユーザーの作成後、STS の AssumeRole 操作を呼び出す権限を付与します。これにより、ユーザーは RAM ロールを引き受けることで一時的な認証情報を取得できるようになります。
-
左側のナビゲーションペインで、[アイデンティティ > ユーザー] を選択します。
-
[ユーザー] ページで、目的の RAM ユーザーを見つけ、操作列の [権限の追加] をクリックします。
-
[権限付与] ページで、[AliyunSTSAssumeRoleAccess] システムポリシーを選択します。
説明[AliyunSTSAssumeRoleAccess] ポリシーは、
AssumeRole操作を呼び出す権限を付与します。これは、OSS リクエストなど、一時的な認証情報を使用する後続の操作に対する権限を付与するものではありません。 -
Grant permissions をクリックします。
ステップ 3: RAM ロールの作成
現在の Alibaba Cloud アカウント用の RAM ロールを作成し、その Alibaba Cloud リソースネーム (ARN) を取得します。RAM ユーザーはこのロールを引き受けます。
-
左側のナビゲーションペインで、[アイデンティティ > ロール] を選択します。
-
[ロールの作成] をクリックします。[プリンシパルタイプ] には [Alibaba Cloud アカウント] を選択します。
-
現在の Alibaba Cloud アカウントを選択し、[OK] をクリックします。
-
ロール名を入力し、[OK] をクリックします。
-
RAM ロール詳細ページで、[コピー] をクリックしてロールの ARN を保存します。
ステップ 4: ファイルアップロードポリシーの作成
最小権限の原則に従い、特定の OSS バケットへのアップロードを制限する RAM ロール用のカスタムポリシーを作成します。
-
左側のナビゲーションペインで、[権限 > ポリシー] を選択します。
-
[ポリシーの作成] をクリックします。
-
[ポリシーの作成] ページで、JSON をクリックし、スクリプト内の
<Bucket name>を、準備 セクションで作成したバケット名web-direct-uploadに置き換えます。{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "oss:PutObject", "Resource": "acs:oss:*:*:<BucketName>/*" } ] } -
ポリシーを設定した後、[OK] をクリックします。
-
[ポリシーの作成] ダイアログボックスで、[ポリシー名] を入力し、[OK] をクリックします。
ステップ 5: RAM ロールへの権限付与
作成したカスタムポリシーを RAM ロールに付与します。これにより、ロールを引き受けた際に必要な権限が付与されます。
-
左側のナビゲーションペインで、[アイデンティティ > ロール] を選択します。
-
[ロール] ページで、目的の RAM ロールを見つけ、[操作] 列の [権限の追加] をクリックします。
-
[権限付与] ページで、[カスタムポリシー] を選択し、作成したポリシーを選択します。
-
[OK] をクリックします。
サーバー側の署名
アクセスキー ID、アクセスキーシークレット、Role ARN などの機密情報は、環境変数として設定することをお勧めします。これにより、コードにハードコーディングすることを避け、認証情報漏洩のリスクを低減できます。
次の手順に従って環境変数を設定します。
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
-
コマンドプロンプト (CMD) で次のコマンドを実行します。
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" -
新しい CMD ウィンドウを開きます。
-
新しい CMD ウィンドウで次のコマンドを実行して、環境変数が設定されていることを確認します。
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET% echo %OSS_STS_ROLE_ARN%
次のサンプルコードを使用して、署名バージョン 4 (推奨) でサーバー上の POST 署名を計算します。ポリシーフォームフィールドの設定の詳細については、「ポリシーフォームフィールド」をご参照ください。
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>
次のサンプルコードは、一時的なアクセス認証情報を取得し、サーバー上で POST 署名を計算する方法を示しています。
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.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 情報。実際のバケット名、リージョン ID、ホストに置き換えてください。
String bucket = "examplebucket";
String region = "cn-hangzhou";
String host = "http://examplebucket.oss-cn-hangzhou.aliyuncs.com";
// アップロードコールバック URL を設定します。これはコールバックサーバーのアドレスです。パブリック URL である必要があります。OSS はこの URL を使用して、オブジェクトのアップロード情報をアプリケーションサーバーに送信します。
// OSS にアップロードされるオブジェクトのプレフィックス (ディレクトリ)。
String upload_dir = "dir";
// 有効期限 (秒単位)。
Long expire_time = 3600L;
/**
* 指定された秒数に基づいて有効期限を生成します。
* @param seconds 秒単位の期間。
* @return "2014-12-01T12:00:00.000Z" などの ISO 8601 時刻文字列。
*/
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 ペアをハードコーディングすることはセキュリティリスクがあるため推奨されません。このコードは参考用です。
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 一時的な認証情報を取得します。
* @return AssumeRoleResponseBodyCredentials オブジェクト。
*/
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);
// credentials オブジェクトには、AccessKeyId、AccessKeySecret、SecurityToken が含まれています。
return response.body.credentials;
} catch (TeaException error) {
// これはデモンストレーション用です。例外は慎重に処理し、プロジェクトでは無視しないでください。
// エラーメッセージ
System.out.println(error.getMessage());
// 診断アドレス
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()));
// System.out.println("stringToSign: " + stringToSign);
// ステップ 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");
// System.out.println("signingKey: " + BinaryUtil.toBase64String(signingKey));
// ステップ 4: 署名を計算します。
byte[] result = hmacsha256(signingKey, stringToSign);
String signature = BinaryUtil.toHex(result);
// System.out.println("signature:" + signature);
Map<String, String> response = new HashMap<>();
// データをマップに追加します。
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);
// PostObject オペレーション用の Web クライアントにステータスコード 200 (OK) の ResponseEntity を返します。
return ResponseEntity.ok(response);
}
public static byte[] hmacsha256(byte[] key, String data) {
try {
// HmacSHA256 キー仕様を初期化します。
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
// HmacSHA256 Mac インスタンスを取得します。
Mac mac = Mac.getInstance("HmacSHA256");
// キーで Mac オブジェクトを初期化します。
mac.init(secretKeySpec);
// データの HMAC 署名を計算します。
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 トークン) を取得し、アップロードポリシーを構築して、サーバー上で POST 署名を計算する方法を示しています。
from flask import Flask, render_template, jsonify
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
from alibabacloud_credentials.client import Client as CredentialClient
import os
import json
import base64
import hmac
import datetime
import time
import hashlib
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
)
# STS クライアントを作成し、一時的な認証情報を取得します。
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')
# ポリシーを構築し、署名を生成します。
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},
]
}
print(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 # セキュリティトークン。
}
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 トークン) を取得し、アップロードポリシーを構築して、サーバー上で POST 署名を計算する方法を示しています。
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.OSS_STS_ROLE_ARN, '', '3600', 'yourRoleSessionName'); // 環境変数から RAM ロール ARN を取得します。一時的なアクセス認証情報は 3,600 秒間有効で、ロールセッション名は 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', // 宛先バケットの名前に置き換えてください。
region: 'cn-hangzhou', // 宛先バケットのリージョンに置き換えてください。
accessKeyId,
accessKeySecret,
stsToken: securityToken,
refreshSTSTokenInterval: 0,
refreshSTSToken: async () => {
const { accessKeyId, accessKeySecret, securityToken } = await client.getCredential();
return { accessKeyId, accessKeySecret, stsToken: securityToken };
},
});
// フォームデータマップを作成します。
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);
// 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'},
{ 'x-oss-credential': credential },
{ 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
{ 'x-oss-date': formattedDate },
],
};
// STS トークンが存在する場合は、ポリシーとフォームデータに追加します。
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);
// フォームデータを返します。
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 にアップロードされるオブジェクトのプレフィックス (ディレクトリ)。
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 トークン) を取得し、アップロードポリシーを構築して、サーバー上で POST 署名を計算する方法を示しています。
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"`
}
func main() {
// デフォルトの IP アドレスとポート文字列を定義します。
strIPPort := ":8000"
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("")
os.Exit(0)
}
// サーバーが実行されているアドレスとポートを出力します。
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 関数は、OSS アップロードに必要な署名と認証情報を生成します。
func getPolicyToken() string {
// バケットのリージョンを設定します。
region = "cn-hangzhou"
// バケット名に置き換えてください。
bucketName = "examplebucket"
// OSS アップロードアドレスを設定します。
host := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com", bucketName, region)
// アップロードディレクトリを設定します。
dir := "user-dir"
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))
// クライアントに返すフォームを構築します。
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, // OSS アップロードアドレス。
Dir: dir, // アップロードディレクトリ。
}
response, err := json.Marshal(policyToken)
if err != nil {
fmt.Println("json err:", err)
}
return string(response)
}
PHP
次のコマンドを実行して依存関係をインストールします。
composer install
次のサンプルコードは、一時的なアクセス認証情報 (STS トークン) を取得し、アップロードポリシーを構築して、サーバー上で POST 署名を計算する方法を示しています。
<?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'; // バケットのドメイン名に置き換えてください。
$expire_time = 3600; // 有効期限 (秒単位)。
$upload_dir = 'user-dir'; // アップロードされるオブジェクトのプレフィックス (ディレクトリ)。
// HMAC-SHA256 を計算します。
function hmacsha256($key, $data) {
return hash_hmac('sha256', $data, $key, true);
}
// POST 署名を取得するリクエストを処理します。
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 リクエストを開始し、結果を取得します。
// を `oss-role-session` などのカスタムセッション名に設定します。
// を、指定された OSS バケットへのファイルアップロード権限を持つ RAM ロールの ARN に置き換えてください。
$result = $request
->withRoleSessionName('oss-role-session')
->withDurationSeconds(3600)
->withRoleArn(getenv('OSS_STS_ROLE_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);
// 署名データを返します。
$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
];
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;
?>
ステップ 3: Web クライアントの設定
クライアントサイドフォームアップロード
Web クライアントがアプリケーションサーバーから必要な情報を受け取った後、HTML フォームリクエストを構築します。このリクエストは Object Storage Service (OSS) と直接通信してファイルをアップロードします。
Web クライアント:サンプルレスポンス
アプリケーションサーバーは、STS トークンとアップロードポリシーを Web クライアントに返します。
{
"dir": "user-dirs",
"host": "http://examplebucket.oss-cn-hangzhou.aliyuncs.com",
"policy": "eyJl****",
"x-oss-security-token": "CAIS****",
"x-oss-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"
}
次の表に、レスポンスボディの各フィールドの説明を示します。
|
パラメーター |
説明 |
|
dir |
アップロードに必須のオブジェクト名のプレフィックスを指定します。 |
|
host |
アップロード先バケットのドメイン名です。 |
|
policy |
ブラウザベースのフォームアップロードに使用されるポリシーです。詳細については、「Post Policy」をご参照ください。 |
|
x-oss-security-token |
STS が提供する、認証用の一時的な認証情報です。 |
|
x-oss-signature |
ポリシーから生成された署名です。詳細については、「Post Signature」をご参照ください。 |
|
x_oss_credential |
署名キーを派生させるために使用するパラメーターセットです。 |
|
x_oss_date |
リクエスト時刻 (ISO 8601 形式)。例: |
|
x_oss_signature_version |
署名バージョンとアルゴリズム。値は OSS4-HMAC-SHA256 に固定されています。 |
-
フォームリクエストには、ファイルコンテンツとアプリケーションサーバーから返されたパラメーターが含まれます。
-
Web クライアントは、このリクエストを使用して OSS と直接通信し、ファイルをアップロードします。
-
fileフォームフィールドを除き、keyを含む他のすべてのフォームフィールドは 8 KB を超えてはなりません。 -
デフォルトでは、Web ベースのアップロードは同名のオブジェクトを上書きします。オブジェクトが上書きされるのを防ぐには、
x-oss-forbid-overwriteフォームフィールドをリクエストに追加し、その値をtrueに設定します。同名のオブジェクトが OSS にすでに存在する場合、アップロードは失敗し、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>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
const form = document.querySelector("form");
const fileInput = document.querySelector("#file");
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("Failed to get signature");
}
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["x-oss-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["x-oss-security-token"]);
formData.append("file", file); // fileは最後のフォームフィールドである必要があります
return fetch(data.host, {
method: "POST",
body: formData
});
})
.then((response) => {
if (response.ok) {
console.log("Upload successful.");
alert("The file was uploaded successfully.");
} else {
console.log("Upload failed", response);
alert("Upload failed. Please try again later.");
}
})
.catch((error) => {
console.error("An error occurred:", error);
});
});
});
</script>
</body>
</html>
-
HTML フォームには、ファイル入力と送信ボタンが含まれています。
-
フォームが送信されると、JavaScript コードはデフォルトの送信を妨げ、必要な署名情報を取得するためにアプリケーションサーバーに AJAX リクエストを送信します。
-
署名情報を受信すると、コードは必要なフォームフィールドを含んだ
FormDataオブジェクトを作成します。 -
次に、
fetchメソッドを使用して OSS URL に POST リクエストを送信し、ファイルをアップロードします。
アップロードが成功すると、「The file was uploaded successfully.」というメッセージが表示されます。アップロードが失敗すると、エラーメッセージが表示されます。
検証
デプロイメント後、アプリケーションサーバーにアクセスして、署名付き URL によるダイレクトアップロード機能をテストします。
-
ブラウザでアプリケーションサーバーにアクセスします。[ファイルを選択] をクリックし、ファイルを選択してアップロードします。
-
バケットページで、作成したバケットを開き、アップロードされたオブジェクトがあることを確認します。
推奨設定
ファイルアップロードポリシー
コード内のポリシーを変更して、HTML フォームから OSS へのファイルアップロードに対する権限と制約を設定できます。JSON 形式のポリシーでは、許可するバケット名、オブジェクトのプレフィックス、有効期限、許可する HTTP メソッド、コンテンツサイズの制限、コンテンツタイプなどのパラメーターを設定することで、アップロードを制限できます。
{
"expiration": "2023-12-03T13:00:00.000Z",
"conditions": [
{"bucket": "examplebucket"},
{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
{"x-oss-credential": "AKIDEXAMPLE/20231203/cn-hangzhou/oss/aliyun_v4_request"},
{"x-oss-security-token": "CAIS******"},
{"x-oss-date": "20231203T121212Z"},
["content-length-range", 1, 10],
["eq", "$success_action_status", "201"],
["starts-with", "$key", "user/eric/"],
["in", "$content-type", ["image/jpeg", "image/png"]],
["not-in", "$cache-control", ["no-cache"]]
]
}
ポリシーパラメーターの詳細については、「POST ポリシー」をご参照ください。
サーバーサイド署名とアップロードコールバック
ファイル名やサイズなど、アップロードされたファイルに関するメタデータを受信するには、アップロードコールバックを設定します。ファイルがアップロードされると、OSS はファイル情報をアプリケーションサーバーに送信します。詳細については、「サーバーサイド署名とアップロードコールバックを使用したダイレクトアップロード」をご参照ください。
CORS オリジンの制限
便宜上、これまでは許可オリジンにワイルドカード文字 * が設定されていました。セキュリティのベストプラクティスとして、ワイルドカードをお使いのアプリケーションサーバーの特定の URL に置き換えてください。これにより、お使いのサーバーからのクロスオリジンリクエストのみが許可されるようになります。
|
パラメーター |
サンプル値 |
|
[ソース] |
|
|
[許可されたメソッド] |
POST、PUT、GET |
|
[許可されたヘッダー] |
* |
リソースのクリーンアップ
このソリューションでは、1 つの ECS インスタンス、1 つの OSS バケット、1 つの RAM ユーザー、および 1 つの RAM ロールを作成しました。テストが完了したら、継続的な料金やセキュリティリスクを回避するために、これらのリソースをクリーンアップしてください。
ECS インスタンスのリリース
インスタンスが不要になった場合は、リリースしてください。インスタンスをリリースすると、課金が停止し、そのデータは復元できなくなります。
-
ECS コンソール の [インスタンス] ページに移動し、リージョンとインスタンス ID で対象の ECS インスタンスを見つけ、[操作] 列の
をクリックします。 -
[リリース] を選択します。表示されるメニューで、 [リリース] をクリックします。
-
インスタンスの詳細を確認し、 [今すぐリリース] を選択してから [次へ] をクリックします。
-
リリースされる関連リソースを確認し、関連するデータリスクに同意してから、 [確認] をクリックします。
-
システムディスクと割り当てられたパブリック IP アドレスは、インスタンスと共にリリースされます。
-
セキュリティグループ、vSwitch、および VPC はインスタンスと共にリリースされません。これらのリソースは無料ですが、不要になった場合は削除できます。
-
EIP はインスタンスと共にリリースされず、料金が継続されます。不要になった場合は、別途削除してください。
OSS バケットの削除
-
OSS コンソール にログインします。
-
バケット をクリックし、対象の OSS バケットの名前をクリックします。
-
バケット内のすべてのオブジェクトを削除します。
-
ナビゲーションペインで バケットの削除 をクリックし、画面の指示に従ってください。
RAM ユーザーの削除
-
管理者権限を持つ RAM ユーザーとして RAM コンソール にログインします。
-
ナビゲーションペインで、 を選択します。
-
[ユーザー] ページで、対象の RAM ユーザーを見つけ、[操作] 列の [削除] をクリックします。
または、複数の RAM ユーザーを選択し、リストの下にある [ユーザーの削除] をクリックして、すべてをごみ箱に移動します。
-
[ユーザーの削除] ダイアログボックスで、削除の影響を慎重に確認し、対象の RAM ユーザーの名前を入力してから、 ごみ箱に移動する をクリックします。
RAM ロールの削除
-
管理者権限を持つ RAM ユーザーとして RAM コンソール にログインします。
-
ナビゲーションペインで、 を選択します。
-
[ロール] ページで、対象の RAM ロールを見つけ、[操作] 列の [ロールの削除] をクリックします。
-
[ロールの削除] ダイアログボックスで、RAM ロール名を入力し、 [ロールの削除] をクリックします。
説明RAM ロールにポリシーがアタッチされている場合、ロールを削除するとポリシーもデタッチされます。
よくある質問
マルチパートアップロードと再開可能なアップロード
このソリューションではフォームアップロードを使用しており、マルチパートアップロードや再開可能なアップロードはサポートしていません。これらの方法を使用するには、「再開可能なアップロード」および「マルチパートアップロード」をご参照ください。
ファイルの上書き防止
アップロードフォームのフィールドで、x-oss-forbid-overwrite パラメーターを true に設定します。例:
formData.append('x-oss-forbid-overwrite', 'true');