すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:アプリケーションサーバーから署名情報を取得し、データを直接 OSS にアップロードする

最終更新日:Nov 11, 2025

Web クライアントから Object Storage Service (OSS) にファイルを直接アップロードするには、PostObject 操作を呼び出すことができます。 アプリケーションサーバーで生成された署名情報を追加して、これらのアップロードを保護し、適切なアップロードポリシーを構成して、ビジネス要件を満たすアップロード制限を実装できます。

ソリューション概要

次の図は、アプリケーションサーバーで署名を生成し、その署名を使用して Web クライアントから OSS にファイルを直接アップロードする方法を示しています。

アプリケーションサーバーから署名情報を取得し、データを OSS にアップロードするには、次の手順を実行します。

説明

このプロセスでは、一時的なアクセス認証情報が使用されます。 これにより、アプリケーションサーバーの AccessKey ペアの漏洩を防ぎ、ファイルアップロードのセキュリティを確保します。

  1. OSS リソースを準備する: まず、アップロードされたデータを格納するバケットを作成し、Web クライアントからのクロスオリジンリクエストを許可するように、バケットのクロスオリジンリソース共有 (CORS) ルールを構成する必要があります。

  2. アプリケーションサーバーを構成する: この手順では、Security Token Service (STS) の対応する操作を呼び出して、一時的なアクセス認証情報のペアを取得する必要があります。 次に、一時的なアクセス認証情報とアプリケーションサーバーにプリセットされたアップロードポリシーを使用して署名を生成し、特定の期間内にファイルをアップロードする権限をユーザーに付与します。 プリセットされたアップロードポリシーには、バケット名、ディレクトリパス、有効期限などの情報が含まれています。

  3. Web クライアントを構成する: HTML フォームを作成し、そのフォームを使用して署名を送信し、オブジェクトを OSS にアップロードします。

デモプロジェクト

手順

手順 1: OSS リソースを準備する

1. バケットを作成する

ブラウザから Web アプリケーションによってアップロードされたデータを格納する OSS バケットを作成します。

  1. OSS コンソール にログインします。

  2. 左側のナビゲーションウィンドウで、バケット をクリックします。 [バケット] ページで、バケットの作成 をクリックします。

  3. バケットの作成 パネルで、次のパラメーターで説明されているパラメーターを構成します。

    パラメーター

    サンプル値

    バケット名

    web-direct-upload

    リージョン

    中国 (杭州)

  4. OK をクリックします。

2. CORS ルールを構成する

作成したバケットの CORS ルールを構成します。

  1. バケット ページで、バケットの名前をクリックします。

  2. 表示されるページの左側のナビゲーションツリーで、[コンテンツセキュリティ] > [CORS] を選択します。 クロスオリジンリソース共有の設定 ページで、ルールの作成 をクリックします。

  3. ルールの作成 パネルで、次の表で説明されているパラメーターを構成します。

    パラメーター

    サンプル値

    ソース

    *

    許可されるメソッド

    POST、PUT、GET

    許可されるヘッダー

    *

  1. OK をクリックします。

手順 2: アプリケーションサーバーを構成する

説明

デプロイメントで既にアプリケーションサーバーが使用可能な場合は、準備手順をスキップして、ユーザー権限の構成 から直接始めることができます。

準備: アプリケーションサーバーとして ECS インスタンスを作成する

操作 1: ECS インスタンスを作成する

Elastic Compute Service (ECS) コンソールのインスタンス購入ページの[カスタム起動] タブで、ECS インスタンスに必要な基本リソースを作成または選択します。

  1. リージョンと課金方法を選択する

    1. ビジネス要件に基づいて課金方法を選択します。 この例では、従量課金制 の課金方法が選択されています。

    2. ネットワークレイテンシ要件に基づいてリージョンを選択します。 通常、対象ユーザーに近いリージョンほど、レイテンシが低く、アクセスが高速になります。 この例では、中国 (杭州) リージョンが選択されています。

      image

  1. 仮想プライベートクラウド (VPC) と vSwitch を作成する

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

    説明

    VPC の作成中に vSwitch を作成することもできます。

    image

    image

    image

  1. インスタンスタイプとイメージを選択する

    インスタンスタイプとイメージを選択します。 選択したイメージによって、オペレーティングシステムとそのバージョンが決まります。 この例では、費用対効果の高い ecs.e-c1m1.large インスタンスタイプと Alibaba Cloud Linux 3.2104 LTS 64 ビット パブリックイメージを使用しています。

    image

  1. ストレージを構成する

    ビジネス要件に基づいて、ECS インスタンスのシステムディスクとデータディスクを構成します。 このデモプロジェクトでは軽量の Web アプリケーションをデプロイするため、システムディスクだけで十分であり、データディスクは構成されていません。

    image

  1. パブリック IP アドレスを割り当てる

    ECS インスタンスにインターネット接続を提供するには、[パブリック IPv4 アドレスを割り当てる] を選択して、インスタンスにパブリック IP アドレスを割り当てます。 あるいは、インスタンスの作成後に、ECS インスタンスに Elastic IP アドレス (EIP) を関連付けることもできます。 詳細については、「EIP を ECS インスタンスに関連付ける」をご参照ください。

    説明
    • ECS インスタンスにパブリック IP アドレスを割り当てたり、EIP を関連付けたりしないと、SSH またはリモートデスクトッププロトコル (RDP) 経由でインスタンスにアクセスしたり、インターネット経由でインスタンスにデプロイされた Web サービスをテストしたりすることはできません。

    • [パブリック IPv4 アドレスを割り当てる] を選択した後、[帯域幅課金方法] を設定して、ネットワーク使用量の課金方法を指定します。 この例では、[帯域幅課金方法] パラメーターは [トラフィック課金] に設定されています。 トラフィック課金方法では、インターネット経由で転送されたデータ量に基づいて課金されます。 詳細については、「パブリック帯域幅」をご参照ください。

    image

  1. セキュリティグループを作成する

    ECS インスタンスのセキュリティグループを作成します。 セキュリティグループは、ECS インスタンスのインバウンドトラフィックとアウトバウンドトラフィックを制御する仮想ファイアウォールとして機能します。 セキュリティグループを作成するときは、次のポートを開いて ECS インスタンスへのアクセスを許可します。

    IPv4 ポート/プロトコルを開く: SSH (TCP:22)、RDP (TCP:3389)、HTTP (TCP:80)、および HTTPS (TCP:443) を選択します。

    説明
    • IPv4 ポート/プロトコルを開く で選択されたポートは、ECS インスタンスで実行されるアプリケーションに開く必要があるポートです。

    • このプロセスで SSH (TCP:22) が選択されている場合、セキュリティグループには、すべての IP アドレスを表す 0.0.0.0/0 からのトラフィックを許可するルールが自動的に含まれます。 このルールでは、指定されたポートで、すべての IP アドレスから ECS インスタンスへのアクセスが許可されます。 インスタンスの作成後、特定の IP アドレスからのみインスタンスへのアクセスを許可するようにルールを変更することをお勧めします。 詳細については、「セキュリティグルールの変更」をご参照ください。

    image

  1. キーペアを作成する

    1. キーペアを ECS インスタンスにバインドし、インスタンスにログインするときに ID を認証するための認証情報として使用できます。 キーペアを作成したら、ECS インスタンスに接続する ときに後で使用するために、キーペアの秘密鍵をダウンロードします。 キーペアを作成したら、インスタンス購入ページの [カスタム起動] タブに戻り、[キーペア] ドロップダウンリストを更新してから、作成したキーペアを選択します。

    2. root は、オペレーティングシステムで最も権限の高いアカウントです。 ログインユーザー名として root を選択すると、セキュリティリスクが発生する可能性があります。 ログインユーザー名として ecs-user を選択することをお勧めします。

      説明

      キーペアを作成すると、キーペアの秘密鍵が自動的にダウンロードされます。 ブラウザのダウンロード履歴を表示して、.pem 形式の秘密鍵ファイルを確認します。

      image

  1. インスタンスの作成を完了し、インスタンスを表示する

    必要なリソースを作成または選択したら、[注文を作成] をクリックします。 成功メッセージで、[コンソール] をクリックして、作成された ECS インスタンスを表示します。 後で使用するために、次の情報を記録します。

    • インスタンス ID: インスタンス ID で ECS インスタンスを検索できます。

    • リージョンとゾーン: リージョンとゾーンで ECS インスタンスを検索できます。

    • パブリック IP アドレス: ECS インスタンスのパブリック IP アドレスを使用して、インスタンスにデプロイされた Web サービスにアクセスできます。

    imageimage

操作 2: ECS インスタンスに接続する

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

  2. [リモート接続] ダイアログボックスで、[ワークベンチ] セクションの [今すぐサインイン] をクリックします。image

  3. [インスタンスログイン] ダイアログボックスで、[接続方法][ターミナル接続] に、[認証方法][SSH キー認証] に設定します。 次に、キーペアの作成時にダウンロードした秘密鍵を入力またはアップロードし、ecs-user として ECS インスタンスに [ログイン] します。

  4. 説明

    キーペアを作成すると、キーペアの秘密鍵ファイルがオンプレミスのコンピューターに自動的にダウンロードされます。 ブラウザのダウンロード履歴を表示して、.pem 形式の秘密鍵ファイルを見つけます。

  5. 次の図に示すようなページが表示されたら、ECS インスタンスにログインしています。image

1. ユーザー権限を構成する

説明

権限が不十分なために OSS へのファイルのアップロードが失敗するのを防ぐために、次の手順を使用して RAM ユーザーに必要な権限を付与することをお勧めします。

操作 1: RAM コンソールで RAM ユーザーを作成する

RAM ユーザーを作成し、RAM ユーザーの AccessKey ペアを取得します。 AccessKey ペアは、アプリケーションへのアクセスと管理に必要な長期アクセス認証情報です。

  1. Alibaba Cloud アカウントを使用して、またはアカウント管理者として、RAM コンソール にログインします。

  2. 左側のナビゲーションウィンドウで、[アイデンティティ] > [ユーザー] を選択します。

  3. [ユーザー] ページで、[ユーザーの作成] をクリックします。

  4. [ログイン名] パラメーターと [表示名] パラメーターを構成します。

  5. [アクセスモード] セクションで、[永続 AccessKey を使用してアクセスする] を選択し、[OK] をクリックします。

重要

RAM ユーザーの AccessKey シークレットは、RAM ユーザーの作成時にのみ取得できます。 認証情報の漏洩を防ぐために、AccessKey シークレットを安全に保管する必要があります。

  1. 表示されるページで、[操作] 列の [コピー] をクリックして AccessKey ペアをコピーし、安全に保管されたファイルに貼り付けます。

操作 2: RAM ユーザーに AssumeRole 操作を呼び出す権限を付与する

RAM ユーザーに AssumeRole 操作を呼び出す権限を付与します。 これにより、RAM ユーザーは RAM ロールを引き受けることで一時的なアクセス認証情報を取得できます。

  1. 左側のナビゲーションウィンドウで、[ID] > ユーザーを選択します。

  2. [ユーザー] ページで、RAM ユーザーを見つけ、[操作] 列の [権限の追加] をクリックします。

  3. [権限の付与] パネルの [ポリシー] セクションで、[AliyunSTSAssumeRoleAccess] ポリシーを選択します。

    説明

    AliyunSTSAssumeRoleAccess ポリシーにより、RAM ユーザーは AssumeRole 操作を呼び出すことができます。 このポリシーは、RAM ユーザーが STS から一時的なアクセス認証情報を取得し、OSS にリクエストを開始するために必要な権限を付与するものではありません。

  4. [権限の付与] をクリックします。

操作 3: RAM コンソールで RAM ロールを作成する

Alibaba Cloud アカウントの RAM ロールを作成し、RAM ロールの Alibaba Cloud リソース名 (ARN) を取得します。 RAM ロールは、後で RAM ユーザーによって引き受けられます。

  1. 左側のナビゲーションウィンドウで、[アイデンティティ] > [ロール] を選択します。

  2. [ロールの作成] をクリックし、[プリンシパルタイプ] パラメーターに [クラウドアカウント] を選択します。

  3. [プリンシパル名] に [現在のアカウント] を選択します。

  4. 表示されるダイアログボックスで、[ロール名] を入力し、[OK] をクリックします。

  5. 表示されるページで、[コピー] をクリックして、ロールの ARN を保存します。

操作 4: RAM コンソールでカスタムポリシーを作成する

最小権限の原則に基づいてカスタムポリシーを作成し、RAM ロールに特定のバケットにのみデータをアップロードする権限を付与します。

  1. 左側のナビゲーションウィンドウで、[権限] > [ポリシー] を選択します。

  2. [ポリシー] ページで、[ポリシーの作成] をクリックします。

  3. [ポリシーの作成] ページで、[JSON] をクリックします。 次のサンプルスクリプトをコピーしてコードエディターに貼り付けます。 <BucketName> を、作成したバケットの名前に置き換えます。この例では web-direct-upload です。

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "oss:PutObject",
          "Resource": "acs:oss:*:*:<BucketName>/*" // バケット名を指定します
        }
      ]
    }
  4. [OK]をクリックします。

  5. [ポリシーの作成] ダイアログボックスで、[ポリシー名] を入力し、[OK] をクリックします。

操作 5: RAM コンソールでカスタムポリシーを RAM ロールにアタッチする

カスタムポリシーを RAM ロールにアタッチします。 これにより、RAM ロールが引き受けられたときに、RAM ロールは必要な権限を提供できます。

  1. 左側のナビゲーションウィンドウで、[アイデンティティ] > [ロール] を選択します。

  2. [ロール] ページで、RAM ロールを見つけ、[操作] 列の [権限の付与] をクリックします。

  3. [権限の付与] パネルで、[カスタムポリシー] を選択し、カスタムポリシーを選択します。

  4. [権限の付与] をクリックします。

2. アプリケーションサーバーで一時的なアクセス認証情報を取得し、署名を計算する

説明

コードで機密情報を明示的に指定することに伴うリスクを回避するために、環境変数を作成して accessKeyIdaccessKeySecretroleArn などの機密情報を格納することをお勧めします。

環境変数を追加するには、次の手順を実行します。

Linux

  1. CLI で次のコマンドを実行して、環境変数の構成を ~/.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
  2. 次のコマンドを実行して変更を適用します。

    source  ~/.bashrc
  3. 次のコマンドを実行して、環境変数が有効になっているかどうかを確認します。

    echo $OSS_ACCESS_KEY_ID
    echo $OSS_ACCESS_KEY_SECRET
    echo $OSS_STS_ROLE_ARN

macOS

  1. ターミナルで次のコマンドを実行して、デフォルトのシェルタイプを表示します。

    echo $SHELL
  2. デフォルトのシェルタイプに基づいて操作を実行します。

    Zsh

    1. 次のコマンドを実行して、環境変数の構成を ~/.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
    2. 次のコマンドを実行して変更を適用します。

      source ~/.zshrc
    3. 次のコマンドを実行して、環境変数が有効になっているかどうかを確認します。

      echo $OSS_ACCESS_KEY_ID
      echo $OSS_ACCESS_KEY_SECRET
      echo $OSS_STS_ROLE_ARN

    Bash

    1. 次のコマンドを実行して、環境変数の構成を ~/.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
    2. 次のコマンドを実行して変更を適用します。

      source ~/.bash_profile
    3. 次のコマンドを実行して、環境変数が有効になっているかどうかを確認します。

      echo $OSS_ACCESS_KEY_ID
      echo $OSS_ACCESS_KEY_SECRET
      echo $OSS_STS_ROLE_ARN

Windows

  1. 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"
  2. 新しい cmd ウィンドウを開きます。

  3. 新しいウィンドウで次のコマンドを実行して、環境変数が有効になっているかどうかを確認します。

    echo %OSS_ACCESS_KEY_ID%
    echo %OSS_ACCESS_KEY_SECRET%
    echo %OSS_STS_ROLE_ARN%

次のサンプルコードを参照して、アプリケーションサーバー上の PostObject リクエストで V4 署名を計算 できます。 PostObject リクエストの policy フォームフィールドについては、「policy」をご参照ください。

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>

次のサンプルコードを参照して、一時的なアクセス認証情報を提供し、PostObject リクエストで使用される署名を計算できます。

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 バケット情報。 実際の情報に置き換えてください。
    String bucket = "examplebucket";
    String region = "cn-hangzhou";
    String host = "http://examplebucket.oss-cn-hangzhou.aliyuncs.com";
    // アップロードコールバックリクエストが送信されるアプリケーションサーバーの URL を指定します。 URL はパブリックドメイン名を使用する必要があります。 この URL は、アプリケーションサーバーと OSS 間の通信に使用されます。 オブジェクトをアップロードした後、OSS はこの URL を使用してアップロード情報をアプリケーションサーバーに送信します。
    // 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;
    }
    // StsClient インスタンスを初期化します。
    public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
        // プロジェクトコードが漏洩した場合、AccessKey ペアが漏洩し、アカウント内のすべてのリソースのセキュリティが侵害される可能性があります。 以下の行は参考としてのみ提供されています。
        // セキュリティの高い 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.alibabacloud.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);
            // 後続の操作に必要な AccessKey ID、AccessKey シークレット、および STS トークンは、認証情報に含まれています。
            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()));
        // 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<>();
        // 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);
        // 200 OK ステータスコードを含む ResponseEntity オブジェクトを Web クライアントに返します。 これにより、クライアントは PostObject 操作を実行できます。
        return ResponseEntity.ok(response);
    }
    public static byte[] hmacsha256(byte[] key, String data) {
        try {
            // SecretKeySpec を初期化し、アルゴリズムを 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("HMAC-SHA256 の計算に失敗しました", e);
        }
    }
}

Python

次のコマンドを実行して依存関係をインストールします。

pip install flask
pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials

次のサンプルコードを参照して、一時的なアクセス認証情報を提供し、PostObject リクエストで使用される署名を計算するためのアップロードポリシーを作成できます。

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'  

# 実際の情報に置き換えてください。
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"HMAC-SHA256 の計算に失敗しました: {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 # STS トークン。

    }
    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

次のサンプルコードを参照して、一時的なアクセス認証情報を提供し、PostObject リクエストで使用される署名を計算するためのアップロードポリシーを作成できます。

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 シークレットを取得します。
    });

    // assumeRole 操作を呼び出して、STS から一時的なアクセス認証情報を取得します。
    const result = await sts.assumeRole(process.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 をバケットが配置されているリージョンの ID に置き換えます。
        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);

    // 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`, // バケットの URL を指定します
        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);
        res.status(500).send('署名の生成中にエラーが発生しました');
    }
});

app.listen(PORT, () => {
    console.log(`サーバーは http://127.0.0.1:${PORT} で実行されています`); // 0.0.0.0 などのパブリックアドレスでリッスンするには、サーバー側で対応する認証メカニズムを実装する必要があります。
});

Go

次のコマンドを実行して依存関係をインストールします。

go get -u github.com/aliyun/credentials-go
go mod tidy

次のサンプルコードを参照して、一時的なアクセス認証情報を提供し、PostObject リクエストで使用される署名を計算するためのアップロードポリシーを作成できます。

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)
    }
    // サーバーの IP アドレスとポートを表示します。
    fmt.Printf("サーバーは %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 を指定します。
    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("OSS_STS_ROLE_ARN"). // 環境変数から RAM ロールの 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, // データのアップロード先の URL。
    Dir:              dir,  // データのアップロード先のディレクトリ。
    }

    response, err := json.Marshal(policyToken)
    if err != nil {
    fmt.Println("json err:", err)
    }
    return string(response)
}

PHP

次のコマンドを実行して依存関係をインストールします。

composer install

次のサンプルコードを参照して、一時的なアクセス認証情報を提供し、PostObject リクエストで使用される署名を計算するためのアップロードポリシーを作成できます。

<?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'; // バケットが配置されているリージョンの ID に置き換えてください。
$host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'; // バケットの URL に置き換えてください。
$expire_time = 3600; // 有効期間を秒単位で指定します。
$upload_dir = 'user-dir'; // オブジェクト名のプレフィックスを指定します。

// 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')) // 環境変数から 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);

    // 署名データを返します。
    $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 クライアントでフォームアップロードリクエストを作成して送信する

Web クライアントがアプリケーションサーバーから必要な情報を受信した後、その情報を使用して HTML フォームアップロードリクエストを構築できます。 リクエストはファイルアップロードのために OSS に直接送信されます。

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"
}

次の表に、メッセージ本文に含まれるフィールドを示します。

フィールド

説明

dir

オブジェクトの名前に含まれるプレフィックス。

host

バケットの URL。

policy

フォームアップロードのポリシー。 詳細については、「ポリシー」をご参照ください。

security_token

STS トークン。

signature

ポリシーの署名文字列。 詳細については、「POST 署名」をご参照ください。

x_oss_credential

派生キーを指定するために使用されるパラメーター。

x_oss_date

リクエストが開始された時刻。 時刻は ISO 8601 標準に従う必要があります。 例: 20231203T121212Z

x_oss_signature_version

署名バージョンと署名の計算に使用されるアルゴリズム。 値は OSS4-HMAC-SHA256 に固定されています。

  • フォームリクエストには、ファイルコンテンツとサーバーから返されたパラメーターが含まれています。

  • Web クライアントは、フォームリクエストを使用して OSS と直接通信し、ファイルをアップロードできます。

説明
  • ファイルフォームフィールドを除き、各フォームフィールド (キーを含む) のサイズは 8 KB を超えることはできません。

  • デフォルトでは、アップロードするオブジェクトと同じ名前の既存のオブジェクトは上書きされます。 既存のオブジェクトを上書きしたくない場合は、アップロードリクエストに x-oss-forbid-overwrite ヘッダーを含め、x-oss-forbid-overwrite ヘッダーを true に設定します。 これにより、宛先パスに既存のオブジェクトと同じ名前のファイルをアップロードすると、アップロードは失敗し、OSS は FileAlreadyExists エラーコードを返します。

<!DOCTYPE html>
<html lang="zh-CN">
<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("署名の取得に失敗しました。");
                }
                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("file", file); // フォームフィールド「file」は最後にする必要があります。

                return fetch(data.host, { 
                    method: "POST",
                    body: formData
                });
            })
            .then((response) => {
                if (response.ok) {
                    console.log("アップロードされました。");
                    alert("ファイルがアップロードされました。");
                } else {
                    console.log("次のレスポンスでアップロードに失敗しました:", response);
                    alert("ファイルのアップロードに失敗しました。 後でもう一度お試しください。");
                }
            })
            .catch((error) => {
                console.error("エラーが発生しました:", error);
            });
    });
});
</script>
</body>
</html>
  • HTML フォームには、ファイル入力フィールドと [送信] ボタンが含まれています。 アップロードするファイルを選択して、フォームを送信できます。

  • フォームを送信すると、JavaScript コードによってデフォルトのフォーム送信がブロックされ、アップロードに必要な署名情報が Asynchronous JavaScript and XML (AJAX) リクエストを使用してサーバーから取得されます。

  • 署名情報を取得した後、必要なすべてのフォームフィールドを含む FormData オブジェクトを構築します。

  • fetch メソッドを使用して、OSS バケットの URL に POST リクエストを送信できます。

ファイルがアップロードされると、「ファイルがアップロードされました。」メッセージが表示されます。 ファイルのアップロードに失敗すると、エラーメッセージが表示されます。

結果を確認する

上記の手順を完了した後、アプリケーションサーバーにアクセスして署名を生成し、Web クライアントから OSS にファイルをアップロードできます。

  1. ブラウザからサーバーにアクセスし、オブジェクトを選択してアップロードします。 次の図は例を示しています。

  2. バケット ページで、アップロードされたオブジェクトを格納するために作成したバケットの名前をクリックします。 表示されるページで、Web クライアントからアップロードしたオブジェクトを表示します。

    image

推奨構成

ファイルのアップロード権限と条件を制限する

サンプルコードの policy 部分を変更して、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/jpg", "image/png"]],
    ["not-in", "$cache-control", ["no-cache"]]
  ]
}

詳細については、「ポリシー」をご参照ください

アップロードコールバックを構成する

アップロードされたオブジェクトに関する詳細情報 (オブジェクト名やサイズなど) を取得する場合は、アップロードコールバックを構成できます。 これにより、ファイルがアップロードされた後にファイルに関する情報が自動的に受信されます。 詳細については、「サーバーに署名を追加し、アップロードコールバックを構成し、データを直接転送する」をご参照ください。

CORS 設定のソースにアプリケーションサーバーの URL を含める

前の CORS 構成手順では、ワイルドカード文字 * を指定して、すべてのソースからのアクセスを許可しました。 セキュリティ上の理由から、許可されるソースを制限することをお勧めします。 たとえば、アプリケーションサーバーの URL を唯一の許可されたソースとして指定できます。 これにより、クロスオリジンアクセスはアプリケーションサーバーからのリクエストに対してのみ許可されます。

パラメーター

サンプル値

ソース

http://<アプリケーションサーバの URL>

許可されたメソッド

POST、PUT、GET

許可されたヘッダー

*

リソースのクリーンアップ

Web アプリケーションを構築するために、ECS インスタンス、OSS バケット、RAM ユーザー、および RAM ロールを作成しました。 確認が完了したら、これらのリソースを解放して、不要な料金を回避し、関連するセキュリティリスクを排除できます。

ECS インスタンスを解放する

作成した ECS インスタンスが不要になった場合は、解放できます。 ECS インスタンスが解放されると、インスタンスの課金は停止し、インスタンス上のデータは失われ、復元できなくなります。 ECS インスタンスを解放するには、次の手順を実行します。

  1. [ECS コンソール]インスタンス ページに移動し、リージョンとインスタンス ID に基づいて ECS インスタンスを見つけ、[操作] 列の image アイコンをクリックします。

  2. [インスタンスステータス] > [解放] を選択します。image

  3. [解放] ダイアログボックスで、[解放設定] に [すぐに解放] を選択し、[次へ] をクリックします。

  4. 解放する関連リソースを確認し、データ損失のリスクに関する注意事項を読み、「解放するインスタンスとそれに関連付けられたリソースを認識しており、データリスクを理解しています」チェックボックスをオンにして、[OK] をクリックします。

説明
  • ECS インスタンスが解放されると、インスタンスのシステムディスクが解放されます。 インスタンスにパブリック IP アドレスが割り当てられている場合、その IP アドレスも解放されます。

  • ECS インスタンスが解放されても、関連付けられているセキュリティグループ、vSwitch、および VPC は解放されません。 セキュリティグループ、vSwitch、または VPC に対しては課金されません。 ビジネス要件に基づいて、保持または解放できます。

  • EIP が ECS インスタンスに関連付けられている場合、インスタンスが解放されても EIP は保持されます。 EIP に対しては課金されます。 ビジネス要件に基づいて、EIP を保持または解放できます。

バケットを削除する

  1. OSS コンソール にログインします。

  2. 左側のナビゲーションウィンドウで、バケット をクリックします。 [バケット] ページで、削除するバケットの名前をクリックします。

  3. バケット内のすべてのオブジェクトを削除してから、バケットを削除します。

  4. 左側のナビゲーションツリーで、バケットの削除 をクリックします。 [バケットの削除] ページで、[バケットの削除] をクリックし、画面の指示に従って削除操作を完了します。

RAM ユーザーを削除する

  1. 管理者権限を持つ RAM ユーザーとして RAM コンソール にログインします。

  2. 左側のナビゲーションウィンドウで、[ID] > [ユーザー] を選択します。

  3. [ユーザー] ページで、削除する RAM ユーザーを見つけ、[操作] 列の [削除] をクリックします。

    複数の RAM ユーザーを選択し、RAM ユーザーリストの下にある [ユーザーの削除] をクリックして、選択したすべての RAM ユーザーを同時にごみ箱に移動することもできます。

  4. [ユーザーの削除] ダイアログボックスで、削除の影響に関するステートメントを読み、RAM ユーザーの名前を入力して、[ごみ箱に移動] をクリックします。

RAM ロールを削除する

  1. 管理者権限を持つ RAM ユーザーとして RAM コンソール にログインします。

  2. 左側のナビゲーションウィンドウで、[ID] > [ロール] を選択します。

  3. [ロール] ページで、削除する RAM ロールを見つけ、[操作] 列の [ロールの削除] をクリックします。

  4. [ロールの削除] ダイアログボックスで、RAM ロールの名前を入力し、[ロールの削除] をクリックします。

    説明

    ポリシーが RAM ロールにアタッチされている場合、RAM ロールを削除するとポリシーはデタッチされます。

参考資料

この直接アップロードソリューションは、マルチパートアップロードとレジュームアップロードをサポートしていますか?

いいえ、このソリューションは HTML フォームを使用してファイルをアップロードするため、マルチパートアップロードや再開可能なアップロードをサポートしていません。マルチパートアップロードまたは再開可能なアップロードを実装する方法については、「再開可能なアップロード」および「マルチパートアップロード」をご参照ください。

ファイルのアップロードによって宛先 OSS パス内の既存のオブジェクトが上書きされないようにするにはどうすればよいですか?

ファイルのアップロードによって宛先 OSS パス内の既存のオブジェクトが上書きされないようにするには、リクエストに x-oss-forbid-overwrite ヘッダーを追加し、その値を true に設定します。 例:

formData.append('x-oss-forbid-overwrite', 'true');