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

Object Storage Service:Browser.js SDK: アクセス権限の付与

最終更新日:Nov 30, 2025

このトピックでは、Security Token Service (STS) と署名付き URL を使用して、Object Storage Service (OSS) リソースへの一時的なアクセス権限を付与する方法について説明します。

権限付与の方法

OSS は、クライアントに権限を付与するための複数の方法をサポートしています。次の表では、3 つの権限付与方法について説明し、それぞれの方法を使用した簡単なアップロードのサンプルコードを示します。認証と権限付与の要件に基づいて、権限付与方法を選択してください。

権限付与の方法

権限付与のプロセス

シナリオ

注意事項

方法 1:サーバーで STS を使用して一時的なアクセス認証情報を生成

  1. クライアントがアプリケーションサーバに一時的なアクセス認証情報をリクエストします。

  2. アプリケーションサーバは Security Token Service (STS) SDK を使用して AssumeRole 操作を呼び出し、一時的なアクセス認証情報を取得します。

  3. STS は一時的なアクセス認証情報を生成し、アプリケーションサーバに返します。

  4. アプリケーションサーバは一時的なアクセス認証情報をクライアントに返します。

  5. クライアントは OSS SDK と一時的なアクセス認証情報を使用して、ファイルを OSS にアップロードします。

  6. OSS は成功の応答をクライアントに返します。

ほとんどのファイルアップロードシナリオでは、サーバー上の STS SDK を使用して一時的なアクセス認証情報を取得することを推奨します。クライアントはこれらの認証情報と OSS SDK を使用してファイルを直接アップロードできます。クライアントは認証情報を再利用して署名を生成することもできます。この方法は、大きなファイルのマルチパートアップロードや再開可能なアップロードに適しています。

STS サービスを頻繁に呼び出すと、スロットリングが発生する可能性があります。一時的な STS 認証情報をキャッシュし、有効期限が切れる前に更新することを推奨します。クライアントが一時的なアクセス認証情報を誤用するのを防ぐために、認証情報にアクセスポリシーを追加して権限をさらに制限することを推奨します。

方法 2:サーバーで PostObject のための署名と PostPolicy を生成

  1. クライアントがアプリケーションサーバに PostObject の署名や PostPolicy などの情報をリクエストします。

  2. アプリケーションサーバは PostObject の署名や PostPolicy などの情報を生成し、クライアントに返します。

  3. クライアントは PostObject の署名と PostPolicy を使用して、HTML フォームから PostObject 操作を呼び出すことでファイルを OSS にアップロードします。

  4. OSS は成功の応答をクライアントに返します。

この方法は、アップロードされるファイルのプロパティを制限する必要があるシナリオに最適です。サーバーで PostObject の署名、PostPolicy、およびその他の必要な情報を生成できます。クライアントは、この情報を使用して、OSS SDK を使用せずに特定の制限下でファイルを直接アップロードできます。たとえば、PostPolicy を使用して、クライアントがアップロードできるファイルのサイズと種類を制限できます。この方法は HTML フォームを使用したファイルのアップロードに適していますが、マルチパートアップロードや再開可能なアップロードはサポートしていません。

この方法は、マルチパートアップロードや再開可能なアップロードをサポートしていません。

方法 3:サーバーで PutObject のための署名付き URL を生成

  1. クライアントがアプリケーションサーバに署名付き URL をリクエストします。

  2. アプリケーションサーバは OSS SDK を使用して PUT リクエスト用の署名付き URL を生成し、クライアントに返します。

  3. クライアントは PUT リクエスト用の署名付き URL を使用して、PutObject 操作を呼び出すことでファイルを OSS にアップロードします。

  4. OSS は成功の応答をクライアントに返します。

単純なファイルアップロードシナリオでは、サーバー上の OSS SDK を使用して PutObject のための署名付き URL を生成できます。クライアントは、その署名付き URL を使用して、OSS SDK を使用せずにファイルを直接アップロードできます。

この方法は、マルチパートアップロードや再開可能なアップロードには適していません。サーバーで各パートの署名付き URL を生成し、それらをクライアントに返すと、サーバーとのやり取りの回数が増え、ネットワークリクエストの複雑さが増します。さらに、クライアントがパートの内容や順序を変更する可能性があり、最終的にマージされたファイルが正しくなくなる可能性があります。

サーバーでの STS を使用した一時的なアクセス認証情報の生成

重要

STS の一時的なアクセス認証情報と署名付き URL には、有効期間を指定する必要があります。一時的なアクセス認証情報を使用して、オブジェクトのアップロードやダウンロードなどの操作を実行するための署名付き URL を生成する場合、有効期間が最も短いものが優先されます。たとえば、一時的なアクセス認証情報の有効期間を 1,200 秒に設定し、その認証情報を使用して生成された署名付き URL の有効期間を 3,600 秒に設定したとします。この場合、署名付き URL が有効期間内であっても、STS の一時的なアクセス認証情報が期限切れになると、その署名付き URL を使用してオブジェクトをアップロードすることはできません。

次の図は、サーバー上の STS からの一時的なアクセス認証情報を使用して、クライアントに OSS へのファイルアップロードを許可するプロセスを示しています。

サンプルコード

以下のコードは、主要なコードスニペットです。完全なコードについては、サンプルプロジェクト sts.zip をご参照ください。

サーバーサイドのサンプルコード

次のサンプルコードは、サーバーで一時的なアクセス認証情報を生成する方法を示しています:

Java

import com.aliyun.sts20150401.Client;
import com.aliyun.sts20150401.models.AssumeRoleRequest;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.models.RuntimeOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.aliyun.teaopenapi.models.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static com.aliyun.teautil.Common.assertAsString;

@RestController
public class StsController {

    @Autowired
    private Client stsClient;

    @GetMapping("/get_sts_token_for_oss_upload")
    public AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials generateStsToken() {
        AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest()
            .setDurationSeconds(3600L)
            // <YOUR_ROLE_SESSION_NAME> をカスタムセッション名 (例: my-website-server) に設定します。
            .setRoleSessionName("<YOUR_ROLE_SESSION_NAME>")
            // <YOUR_ROLE_ARN> を、指定された OSS バケットにファイルをアップロードする権限を持つ RAM ロールの ARN に置き換えます。ロールの ARN は RAM ロールの詳細から取得できます。
        RuntimeOptions runtime = new RuntimeOptions();
        try {
            AssumeRoleResponse response = stsClient.assumeRoleWithOptions(assumeRoleRequest, runtime);
            return response.body.credentials;
        } catch (TeaException error) {
            // 必要に応じて、エラーをログに記録します。
            assertAsString(error.message);
            return null;
        } catch (Exception error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // 必要に応じて、エラーをログに記録します。
            assertAsString(error.message);
            return null;
        }
    }
}

@Configuration
public class StsClientConfiguration {

    @Bean
    public Client stsClient() {
        // 認証情報クライアントを初期化する際にパラメータを渡さない場合、認証情報ツールはデフォルトのプロバイダーチェーンを使用してクライアントを初期化します。
        Config config = new Config();
        config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
        try {
            com.aliyun.credentials.Client credentials = new com.aliyun.credentials.Client();
            config.setCredential(credentials);
            return new Client(config);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Node.js

const express = require("express");
const { STS } = require('ali-oss');

const app = express();
const path = require("path");

app.use(express.static(path.join(__dirname, "templates")));
// ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
const accessKeyId = process.env.ALIBABA_CLOUD_ACCESS_KEY_ID;
// ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
const accessKeySecret = process.env.ALIBABA_CLOUD_ACCESS_SECRET;

app.get('/get_sts_token_for_oss_upload', (req, res) => {
  let sts = new STS({
   accessKeyId: accessKeyId,
   accessKeySecret: accessKeySecret
 });
   // roleArn をステップ 2 で取得したロール ARN (例: acs:ram::175708322470****:role/ramtest) に設定します。
   // カスタムポリシーを指定して、STS の一時的なアクセス認証情報の権限をさらに制限します。ポリシーを指定しない場合、返される STS の一時的なアクセス認証情報は、デフォルトで指定されたロールのすべての権限を持ちます。
   // 3000 は秒単位の有効期限です。
   // sessionName を使用して、異なるトークンを区別するためのカスタムロールセッション名 (例: sessiontest) を指定します。
   sts.assumeRole('<YOUR_ROLE_ARN>', ``, '3000', 'sessiontest').then((result) => {
     console.log(result);
     res.json({
       AccessKeyId: result.credentials.AccessKeyId,
       AccessKeySecret: result.credentials.AccessKeySecret,
       SecurityToken: result.credentials.SecurityToken,
     });
   }).catch((err) => {
     console.log(err);
     res.status(400).json(err.message);
   });
 });

app.listen(8000, () => {
  console.log("http://127.0.0.1:8000");
});

Python

import json
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

# <YOUR_ROLE_ARN> を、指定された OSS バケットにファイルをアップロードする権限を持つ RAM ロールの ARN に置き換えます。
role_arn_for_oss_upload = '<YOUR_ROLE_ARN>'
# <YOUR_REGION_ID> を STS サービスのリージョン (例: cn-hangzhou) に設定します。
region_id = '<YOUR_REGION_ID>'

def get_sts_token():
    # CredentialClient を初期化する際にパラメータを指定しない場合、デフォルトのプロバイダーチェーンが使用されます。
    # プログラムをローカルで実行する場合、ALIBABA_CLOUD_ACCESS_KEY_ID と ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を使用して AccessKey ペアを指定できます。
    # プログラムを ECS インスタンス、ECI インスタンス、またはコンテナーで実行する場合、ALIBABA_CLOUD_ECS_METADATA 環境変数を使用してアタッチされたインスタンス RAM ロールを指定できます。SDK は自動的に STS の一時的な認証情報を取得します。
    config = Config(region_id=region_id, credential=CredentialClient())
    sts_client = Sts20150401Client(config=config)
    assume_role_request = sts_20150401_models.AssumeRoleRequest(
        role_arn=role_arn_for_oss_upload,
        # <YOUR_ROLE_SESSION_NAME> をカスタムセッション名 (例: oss-role-session) に設定します。
        role_session_name='<YOUR_ROLE_SESSION_NAME>'
    )
    response = sts_client.assume_role(assume_role_request)
    token = json.dumps(response.body.credentials.to_map())
    return token

Go

package main

import (
    "encoding/json"
    "net/http"
    "os"

    openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
    sts20150401 "github.com/alibabacloud-go/sts-20150401/v2/client"
    util "github.com/alibabacloud-go/tea-utils/v2/service"
    "github.com/alibabacloud-go/tea/tea"
)

/**
 * AccessKey ペアを使用してアカウントクライアントを初期化します。
 * @param accessKeyId
 * @param accessKeySecret
 * @return Client
 * @throws Exception
 */
func CreateClient(accessKeyId *string, accessKeySecret *string) (*sts20150401.Client, error) {
    config := &openapi.Config{
    // 必須。ご利用の AccessKey ID。
    AccessKeyId: accessKeyId,
    // 必須。ご利用の AccessKey Secret。
    AccessKeySecret: accessKeySecret,
    }
    // エンドポイントの詳細については、https://api.aliyun.com/product/Sts をご参照ください。
    config.Endpoint = tea.String("sts.cn-hangzhou.aliyuncs.com")
    return sts20150401.NewClient(config)
}

func AssumeRole(client *sts20150401.Client) (*sts20150401.AssumeRoleResponse, error) {
    assumeRoleRequest := &sts20150401.AssumeRoleRequest{
    DurationSeconds: tea.Int64(3600),
    RoleArn:         tea.String("acs:ram::1379186349531844:role/admin-oss"),
    RoleSessionName: tea.String("peiyu-demo"),
    }
    return client.AssumeRoleWithOptions(assumeRoleRequest, &util.RuntimeOptions{})
}

func handler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
    http.ServeFile(w, r, "templates/index.html")
    return
    } else if r.URL.Path == "/get_sts_token_for_oss_upload" {
    client, err := CreateClient(tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")), tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")))
    if err != nil {
    panic(err)
    }
    assumeRoleResponse, err := AssumeRole(client)
    if err != nil {
    panic(err)
    }
    responseBytes, err := json.Marshal(assumeRoleResponse)
    if err != nil {
    panic(err)
    }
    w.Header().Set("Content-Type", "application/json")
    w.Write(responseBytes)
    return
    }
    http.NotFound(w, r)
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

PHP

<?php
require_once 'vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;
// Alibaba Cloud クライアントを初期化します。
AlibabaCloud::accessKeyClient(getenv('ALIBABA_CLOUD_ACCESS_KEY_ID'), getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'))
    ->regionId('cn-hangzhou')
    ->asDefaultClient();
// STS リクエストを作成します。
$request = Sts::v20150401()->assumeRole();
// STS リクエストを送信し、結果を取得します。
// <YOUR_ROLE_SESSION_NAME> をカスタムセッション名 (例: oss-role-session) に設定します。
// <YOUR_ROLE_ARN> を、指定された OSS バケットにファイルをアップロードする権限を持つ RAM ロールの ARN に置き換えます。
$result = $request
    ->withRoleSessionName("<YOUR_ROLE_SESSION_NAME>")
    ->withDurationSeconds(3600)
    ->withRoleArn("<YOUR_ROLE_ARN>")
    ->request();
// STS リクエストの結果から認証情報を取得します。
$credentials = $result->get('Credentials');
// 返す JSON データを構築します。
$response = [
    'AccessKeyId' => $credentials['AccessKeyId'],
    'AccessKeySecret' => $credentials['AccessKeySecret'],
    'SecurityToken' => $credentials['SecurityToken'],
];
// 応答ヘッダーを application/json に設定します。
header('Content-Type: application/json');
// 結果を JSON 形式に変換して出力します。
echo json_encode(['Credentials' => $response]);
?>

C#

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Aliyun.OSS;
using System;
using System.IO;
using AlibabaCloud.SDK.Sts20150401;
using System.Text.Json;
namespace YourNamespace
{
    public class Program
    {
        private ILogger<Program> _logger;
        public static AlibabaCloud.SDK.Sts20150401.Client CreateClient(string accessKeyId, string accessKeySecret)
        {
            var config = new AlibabaCloud.OpenApiClient.Models.Config
            {
                AccessKeyId = accessKeyId,
                AccessKeySecret = accessKeySecret,
                Endpoint = "sts.cn-hangzhou.aliyuncs.com"
            };
            return new AlibabaCloud.SDK.Sts20150401.Client(config);
        }
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            var app = builder.Build();
            builder.Logging.AddConsole();
            var serviceProvider = builder.Services.BuildServiceProvider();
            var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
            app.UseStaticFiles();
            app.MapGet("/", async (context) =>
            {
                var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
                var htmlContent = await File.ReadAllTextAsync(filePath);
                await context.Response.WriteAsync(htmlContent);
                logger.LogInformation("GET request to root path");
            });
            app.MapGet("/get_sts_token_for_oss_upload", async (context) =>
            {
                var program = new Program(logger);
                var client = CreateClient(Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID"), Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
                var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
                // <YOUR_ROLE_SESSION_NAME> をカスタムセッション名 (例: oss-role-session) に設定します。
                assumeRoleRequest.RoleSessionName = "<YOUR_ROLE_SESSION_NAME>";
                // <YOUR_ROLE_ARN> を、指定された OSS バケットにファイルをアップロードする権限を持つ RAM ロールの ARN に置き換えます。
                assumeRoleRequest.RoleArn = "<YOUR_ROLE_ARN>";
                assumeRoleRequest.DurationSeconds = 3600;
                var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
                var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
                var credentials = response.Body.Credentials;
                var jsonResponse = JsonSerializer.Serialize(new
                {
                    AccessKeyId = credentials.AccessKeyId,
                    AccessKeySecret = credentials.AccessKeySecret,
                    Expiration = credentials.Expiration,
                    SecurityToken = credentials.SecurityToken
                });
                context.Response.ContentType = "application/json";
                await context.Response.WriteAsync(jsonResponse);
            });
            app.Run();
        }
        public Program(ILogger<Program> logger)
        {
            _logger = logger;
        }
    }
}

Ruby

require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
require 'aliyunsdkcore'

# public フォルダのパスを現在のディレクトリの templates フォルダに設定します。
set :public_folder, File.dirname(__FILE__) + '/templates'

def get_sts_token_for_oss_upload()
  client = RPCClient.new(
    # ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
    access_key_id: ENV['ALIBABA_CLOUD_ACCESS_KEY_ID'],
    # ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
    access_key_secret: ENV['ALIBABA_CLOUD_ACCESS_KEY_SECRET'],
    endpoint: 'https://sts.cn-hangzhou.aliyuncs.com',
    api_version: '2015-04-01'
  )
  response = client.request(
    action: 'AssumeRole',
    params: {
      # RoleArn をステップ 2 で取得したロール ARN (例: acs:ram::175708322470****:role/ramtest) に設定します。
      "RoleArn": "acs:ram::175708322470****:role/ramtest",
      # 3600 は秒単位の有効期限です。
      "DurationSeconds": 3600,
      # RoleSessionName を使用して、異なるトークンを区別するためのカスタムロールセッション名 (例: sessiontest) を指定します。
      "RoleSessionName": "sessiontest"
    },
    opts: {
      method: 'POST',
      format_params: true
    }
  )
end

if ARGV.length == 1 
  $server_port = ARGV[0]
elsif ARGV.length == 2
  $server_ip = ARGV[0]
  $server_port = ARGV[1]
end

$server_ip = "0.0.0.0"
$server_port = 8000

puts "App server is running on: http://#{$server_ip}:#{$server_port}"

set :bind, $server_ip
set :port, $server_port

get '/get_sts_token_for_oss_upload' do
  token = get_sts_token_for_oss_upload()
  response = {
    "AccessKeyId" => token["Credentials"]["AccessKeyId"],
    "AccessKeySecret" => token["Credentials"]["AccessKeySecret"],
    "SecurityToken" => token["Credentials"]["SecurityToken"]
  }
  response.to_json
end

get '/*' do
  puts "********************* GET "
  send_file File.join(settings.public_folder, 'index.html')
end

クライアントサイドのサンプルコード

次のサンプルコードは、一時的なアクセス認証情報を使用して Web クライアントから OSS にファイルをアップロードする方法を示しています:

let credentials = null;
const form = document.querySelector("form");
form.addEventListener("submit", async (event) => {
  event.preventDefault();
  // STS サービスへの呼び出しを減らすため、現在の認証情報が期限切れになった場合にのみ、一時的な認証情報を再取得します。
  if (isCredentialsExpired(credentials)) {
    const response = await fetch("/get_sts_token_for_oss_upload", {
      method: "GET",
    });
    if (!response.ok) {
      // エラーの HTTP ステータスコードを処理します。
      throw new Error(
        `Failed to obtain the STS token: ${response.status} ${response.statusText}`
      );
    }
    credentials = await response.json();
  }
  const client = new OSS({
    // <YOUR_BUCKET> をご利用の OSS バケットの名前に設定します。
    bucket: "<YOUR_BUCKET>",
    // <YOUR_REGION> を OSS バケットが配置されているリージョン (例: region: 'oss-cn-hangzhou') に設定します。
    region: "oss-<YOUR_REGION>",
    authorizationV4: true,
    accessKeyId: credentials.AccessKeyId,
    accessKeySecret: credentials.AccessKeySecret,
    stsToken: credentials.SecurityToken,
  });

  const fileInput = document.querySelector("#file");
  const file = fileInput.files[0];
  const result = await client.put(file.name, file);
  console.log(result);
});

/**
 * 一時的な認証情報が期限切れになったかどうかを確認します。
 **/
function isCredentialsExpired(credentials) {
  if (!credentials) {
    return true;
  }
  const expireDate = new Date(credentials.Expiration);
  const now = new Date();
  // 有効期間が 1 分未満の場合、認証情報は期限切れと見なされます。
  return expireDate.getTime() - now.getTime() <= 60000;
}

サーバーでの PostObject のための署名と PostPolicy の生成

次の図は、サーバー上の署名と PostPolicy を使用して、クライアントに OSS へのファイルアップロードを許可するプロセスを示しています。

サンプルコード

以下のコードは、主要なコードスニペットです。完全なコードについては、サンプルプロジェクト postsignature.zip をご参照ください。

サーバーサイドのサンプルコード

次のサンプルコードは、サーバーで PostObject の署名や PostPolicy などの情報を生成する方法を示しています:

Java

import com.aliyun.help.demo.uploading_to_oss_directly_postsignature.config.OssConfig;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.codehaus.jettison.json.JSONObject;
import java.util.Date;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import javax.annotation.PreDestroy;

@Controller
public class PostSignatureController {
    @Autowired
    private OSS ossClient;

    @Autowired
    private OssConfig ossConfig;

    @GetMapping("/get_post_signature_for_oss_upload")
    @ResponseBody
    public String generatePostSignature() {
        JSONObject response = new JSONObject();
        try {
            long expireEndTime = System.currentTimeMillis() + ossConfig.getExpireTime() * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, ossConfig.getDir());
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);
            response.put("ossAccessKeyId", ossConfig.getAccessKeyId());
            response.put("policy", encodedPolicy);
            response.put("signature", postSignature);
            response.put("dir", ossConfig.getDir());
            response.put("host", ossConfig.getHost());
        } catch (
    OSSException oe) {
        System.out.println("Caught an OSSException, which means your request made it to OSS, "
                + "but was rejected with an error response for some reason.");
        // このメソッドが存在すると仮定します。
        System.out.println("HTTP Status Code: " + oe.getRawResponseError()); 
        System.out.println("Error Message: " + oe.getErrorMessage());
        System.out.println("Error Code:       " + oe.getErrorCode());
        System.out.println("Request ID:      " + oe.getRequestId());
        System.out.println("Host ID:           " + oe.getHostId());
    } catch (ClientException ce) {
        System.out.println("Caught an ClientException, which means the client encountered "
                + "a serious internal problem while trying to communicate with OSS, "
                + "such as not being able to access the network.");
        System.out.println("Error Message: " + ce.getMessage());
    } finally {
        if (ossClient != null) {
            ossClient.shutdown();
        }
        return response.toString();
    }
  }
}

@Configuration
public class OssConfig {
    /**
     * <YOUR-ENDPOINT> をエンドポイント (例: oss-cn-hangzhou.aliyuncs.com) に置き換えます。
     */
    private String endpoint = "<YOUR-ENDPOINT>";
    /**
     * <YOUR-BUCKET> をバケット名に置き換えます。
     */
    private String bucket = "<YOUR-BUCKET>";
    /**
     * OSS にアップロードするファイルのプレフィックスを指定します。
     */
    private String dir = "user-dir-prefix/";
    /**
     * 有効期限を秒単位で指定します。
     */
    private long expireTime = 3600;
    /**
     * ホストを構築します。
     */
    private String host = "http://" + bucket + "." + endpoint;
    /**
     * ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を使用して accessKeyId を設定します。
     */
    private String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
    /**
     * ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を使用して accessKeySecret を設定します。
     */
    private String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");

    private OSS ossClient;
    @Bean
    public OSS getOssClient() {
        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        return ossClient;
    }
    @Bean
    public String getHost() {
        return host;
    }
    @Bean
    public String getAccessKeyId() {
        return accessKeyId;
    }
    @Bean
    public long getExpireTime() {
        return expireTime;
    }
    @Bean
    public String getDir() {
        return dir;
    }

    @PreDestroy
    public void onDestroy() {
        ossClient.shutdown();
    }
}

Node.js

const express = require("express");
const { Buffer } = require("buffer");
const OSS = require("ali-oss");
const app = express();
const path = require("path");
const config = {
  // ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
  accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
  // ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
  accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
  // <YOUR-BUCKET> をバケット名に置き換えます。
  bucket: "<YOUR-BUCKET>",
  // OSS にアップロードするファイルのプレフィックスを指定します。
  dir: "prefix/",
};

app.use(express.static(path.join(__dirname, "templates")));

app.get("/get_post_signature_for_oss_upload", async (req, res) => {
  const client = new OSS(config);
  const date = new Date();
  // 署名の有効期間を秒単位で設定します。
  date.setSeconds(date.getSeconds() + 3600);
  const policy = {
    expiration: date.toISOString(),
    conditions: [
      // アップロードするファイルのサイズ制限を設定します。
      ["content-length-range", 0, 1048576000],
      // ファイルをアップロードできるバケットを指定します。
      { bucket: client.options.bucket },
    ],
  };
  const formData = await client.calculatePostSignature(policy);
  const host = `http://${config.bucket}.${
    (await client.getBucketLocation()).location
  }.aliyuncs.com`.toString();
  const params = {
    policy: formData.policy,
    signature: formData.Signature,
    ossAccessKeyId: formData.OSSAccessKeyId,
    host,
    dir: config.dir,
  };
  res.json(params);
});

app.get(/^(.+)*\.(html|js)$/i, async (req, res) => {
  res.sendFile(path.join(__dirname, "./templates", req.originalUrl));
});

app.listen(8000, () => {
  console.log("http://127.0.0.1:8000");
});

Python

import os
from hashlib import sha1 as sha
import json
import base64
import hmac
import datetime
import time

# OSS_ACCESS_KEY_ID 環境変数を設定します。
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
# OSS_ACCESS_KEY_SECRET 環境変数を設定します。
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
# <YOUR_BUCKET> をバケット名に置き換えます。
bucket = '<YOUR_BUCKET>'
# ホストは bucketname.endpoint の形式です。<YOUR_BUCKET> をバケット名に置き換えます。<YOUR_ENDPOINT> を OSS エンドポイント (例: oss-cn-hangzhou.aliyuncs.com) に置き換えます。
host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
# OSS にアップロードするファイルのプレフィックスを指定します。
upload_dir = 'user-dir-prefix/'
# 有効期限を秒単位で指定します。
expire_time = 3600


def generate_expiration(seconds):
    """
    有効期間を秒単位で指定して有効期限を生成します。
    :param seconds: 秒単位の有効期間。
    :return: ISO 8601 形式の時間文字列 (例: "2014-12-01T12:00:00.000Z")。
    """
    now = int(time.time())
    expiration_time = now + seconds
    gmt = datetime.datetime.utcfromtimestamp(expiration_time).isoformat()
    gmt += 'Z'
    return gmt


def generate_signature(access_key_secret, expiration, conditions, policy_extra_props=None):
    """
    署名文字列を生成します。
    :param access_key_secret: 宛先バケットへのアクセス権限を持つアカウントの AccessKey Secret。
    :param expiration: ISO 8601 標準での署名の有効期限。時間は UTC で、yyyy-MM-ddTHH:mm:ssZ 形式である必要があります。例: "2014-12-01T12:00:00.000Z"。
    :param conditions: アップロードフォームで設定できる値を制限するために使用されるポリシー条件。
    :param policy_extra_props: 追加のポリシーパラメータ。将来的にポリシーに新しいパラメータが追加された場合、辞書として渡すことができます。
    :return: signature、署名文字列。
    """
    policy_dict = {
        'expiration': expiration,
        'conditions': conditions
    }
    if policy_extra_props is not None:
        policy_dict.update(policy_extra_props)
    policy = json.dumps(policy_dict).strip()
    policy_encode = base64.b64encode(policy.encode())
    h = hmac.new(access_key_secret.encode(), policy_encode, sha)
    sign_result = base64.b64encode(h.digest()).strip()
    return sign_result.decode()

def generate_upload_params():
    policy = {
        # 有効期間。
        "expiration": generate_expiration(expire_time),
        # 制約。
        "conditions": [
            # success_action_redirect が指定されていない場合、アップロード成功後に返されるステータスコードはデフォルトで 204 です。
            ["eq", "$success_action_status", "200"],
            # フォームフィールドの値は指定されたプレフィックスで始まる必要があります。たとえば、key の値が user/user1 で始まるように指定するには、これを ["starts-with", "$key", "user/user1"] に設定します。
            ["starts-with", "$key", upload_dir],
            # アップロードされるオブジェクトの最小および最大許容サイズをバイト単位で制限します。
            ["content-length-range", 1, 1000000],
            # アップロードされるファイルを指定された画像タイプに制限します。
            ["in", "$content-type", ["image/jpg", "image/png"]]
        ]
    }
    signature = generate_signature(access_key_secret, policy.get('expiration'), policy.get('conditions'))
    response = {
        'policy': base64.b64encode(json.dumps(policy).encode('utf-8')).decode(),
        'ossAccessKeyId': access_key_id,
        'signature': signature,
        'host': host,
        'dir': upload_dir
        # 必要に応じて、ここに他のパラメータを追加できます。
    }
    return json.dumps(response)

Go

package main

import (
    "crypto/hmac"
    "crypto/sha1"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "time"
)

var (
    // ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
    accessKeyId = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
    // ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
    accessKeySecret = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
    // ホストは bucketname.endpoint の形式です。${your-bucket} をバケット名に置き換えます。${your-endpoint} を OSS エンドポイント (例: oss-cn-hangzhou.aliyuncs.com) に置き換えます。
    host = "http://${your-bucket}.${your-endpoint}"
    // OSS にアップロードするファイルのプレフィックスを指定します。
    uploadDir = "user-dir-prefix/"
    // 有効期限を秒単位で指定します。
    expireTime = int64(3600)
)

type ConfigStruct struct {
    Expiration string     `json:"expiration"`
    Conditions [][]string `json:"conditions"`
}
type PolicyToken struct {
    AccessKeyId string `json:"ossAccessKeyId"`
    Host        string `json:"host"`
    Signature   string `json:"signature"`
    Policy      string `json:"policy"`
    Directory   string `json:"dir"`
}

func getGMTISO8601(expireEnd int64) string {
    return time.Unix(expireEnd, 0).UTC().Format("2006-01-02T15:04:05Z")
}
func getPolicyToken() string {
    now := time.Now().Unix()
    expireEnd := now + expireTime
    tokenExpire := getGMTISO8601(expireEnd)
    var config ConfigStruct
    config.Expiration = tokenExpire
    var condition []string
    condition = append(condition, "starts-with")
    condition = append(condition, "$key")
    condition = append(condition, uploadDir)
    config.Conditions = append(config.Conditions, condition)
    result, err := json.Marshal(config)
    if err != nil {
    fmt.Println("callback json err:", err)
    return ""
    }
    encodedResult := base64.StdEncoding.EncodeToString(result)
    h := hmac.New(sha1.New, []byte(accessKeySecret))
    io.WriteString(h, encodedResult)
    signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
    policyToken := PolicyToken{
    AccessKeyId: accessKeyId,
    Host:        host,
    Signature:   signedStr,
    Policy:      encodedResult,
    Directory:   uploadDir,
    }
    response, err := json.Marshal(policyToken)
    if err != nil {
    fmt.Println("json err:", err)
    return ""
    }
    return string(response)
}
func handler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/" {
    http.ServeFile(w, r, "templates/index.html")
    return
    } else if r.URL.Path == "/get_post_signature_for_oss_upload" {
    policyToken := getPolicyToken()
    w.Header().Set("Content-Type", "application/json")
    w.Write([]byte(policyToken))
    return
    }
    http.NotFound(w, r)
}
func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

PHP

<?php
function gmt_iso8601($time)
{
    return str_replace('+00:00', '.000Z', gmdate('c', $time));
}

// 環境変数からアクセス認証情報を取得します。このサンプルコードを実行する前に、ALIBABA_CLOUD_ACCESS_KEY_ID と ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
$accessKeyId = getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
$accessKeySecret = getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// $host の形式は <YOUR-BUCKET>.<YOUR-ENDPOINT> です。実際の情報に置き換えてください。
$host = 'http://<YOUR-BUCKET>.<YOUR-ENDPOINT>';
// ユーザーがファイルをアップロードする際に指定するプレフィックス。
$dir = 'user-dir-prefix/';          

$now = time();
//このポリシーのタイムアウト期間を 10 秒に設定します。これは、この有効期間を過ぎると、ポリシーがアクセスに使用できなくなることを意味します。
$expire = 30;  
$end = $now + $expire;
$expiration = gmt_iso8601($end);

//最大ファイルサイズ。必要に応じて設定できます。
$condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
$conditions[] = $condition;

// ユーザーがアップロードするデータは $dir で始まる必要があります。そうでない場合、アップロードは失敗します。このステップは任意ですが、ユーザーがポリシーを通じて他のユーザーのディレクトリにファイルをアップロードするのを防ぐため、セキュリティ上の理由から推奨されます。
$start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
$conditions[] = $start;


$arr = array('expiration' => $expiration, 'conditions' => $conditions);
$policy = json_encode($arr);
$base64_policy = base64_encode($policy);
$string_to_sign = $base64_policy;
$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $accessKeySecret, true));

$response = array();
$response['ossAccessKeyId'] = $accessKeyId;
$response['host'] = $host;
$response['policy'] = $base64_policy;
$response['signature'] = $signature;
$response['dir'] = $dir;  
echo json_encode($response);

Ruby

require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'

# public フォルダのパスを現在のディレクトリの templates フォルダに設定します。
set :public_folder, File.dirname(__FILE__) + '/templates'

# ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
$access_key_id = ENV['ALIBABA_CLOUD_ACCESS_ID']
# ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
$access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_SECRET']

# $host は <bucketname>.<endpoint> の形式です。実際の情報に置き換えてください。
$host = 'http://<bucketname>.<endpoint>';

# ユーザーがファイルをアップロードする際に指定するプレフィックス。
$upload_dir = 'user-dir-prefix/'
# 有効期限 (秒)。
$expire_time = 30
$server_ip = "0.0.0.0"
$server_port = 8000

if ARGV.length == 1 
  $server_port = ARGV[0]
elsif ARGV.length == 2
  $server_ip = ARGV[0]
  $server_port = ARGV[1]
end

puts "App server is running on: http://#{$server_ip}:#{$server_port}"

def hash_to_jason(source_hash)
  jason_string = source_hash.to_json;    

  jason_string.gsub!("\":[", "\": [")
  jason_string.gsub!("\",\"", "\", \"")
  jason_string.gsub!("],\"", "], \"")
  jason_string.gsub!("\":\"", "\": \"")

  jason_string
end


def get_token()
  expire_syncpoint = Time.now.to_i + $expire_time
  expire = Time.at(expire_syncpoint).utc.iso8601()
  response.headers['expire'] = expire
  policy_dict = {}
  condition_arrary = Array.new
  array_item = Array.new
  array_item.push('starts-with')
  array_item.push('$key')
  array_item.push($upload_dir)
  condition_arrary.push(array_item)
  policy_dict["conditions"] = condition_arrary
  policy_dict["expiration"] = expire
  policy = hash_to_jason(policy_dict)
  policy_encode = Base64.strict_encode64(policy).chomp;
  h = OpenSSL::HMAC.digest('sha1', $access_key_secret, policy_encode)
  hs = Digest::MD5.hexdigest(h)
  sign_result = Base64.strict_encode64(h).strip()
  token_dict = {}
  token_dict['ossAccessKeyId'] = $access_key_id
  token_dict['host'] = $host
  token_dict['policy'] = policy_encode
  token_dict['signature'] = sign_result 
  token_dict['expire'] = expire_syncpoint
  token_dict['dir'] = $upload_dir
  result = hash_to_jason(token_dict)
  result
end

set :bind, $server_ip
set :port, $server_port

get '/get_post_signature_for_oss_upload' do
  token = get_token()
  puts "Token: #{token}"
  token
end

get '/*' do
  puts "********************* GET "
  send_file File.join(settings.public_folder, 'index.html')
end

end

if ARGV.length == 1 
  $server_port = ARGV[0]
elsif ARGV.length == 2
  $server_ip = ARGV[0]
  $server_port = ARGV[1]
end

$server_ip = "0.0.0.0"
$server_port = 8000

puts "App server is running on: http://#{$server_ip}:#{$server_port}"

set :bind, $server_ip
set :port, $server_port

get '/get_sts_token_for_oss_upload' do
  token = get_sts_token_for_oss_upload()
  response = {
    "AccessKeyId" => token["Credentials"]["AccessKeyId"],
    "AccessKeySecret" => token["Credentials"]["AccessKeySecret"],
    "SecurityToken" => token["Credentials"]["SecurityToken"]
  }
  response.to_json
end

get '/*' do
  puts "********************* GET "
  send_file File.join(settings.public_folder, 'index.html')
end

C#

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.Collections.Generic;
using System;
using System.Globalization;
using System.Text;
using System.Security.Cryptography;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace YourNamespace
{
    public class Program
    {
        private ILogger<Program> _logger;
        // ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
        public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
        // ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
        public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        // ホストは bucketname.endpoint の形式です。<YOUR-BUCKET> をバケット名に置き換えます。<YOUR-ENDPOINT> を OSS エンドポイント (例: oss-cn-hangzhou.aliyuncs.com) に置き換えます。
        public string Host { get; set; } = "<YOUR-BUCKET>.<YOUR-ENDPOINT>";
        // OSS にアップロードするファイルのプレフィックスを指定します。
        public string UploadDir { get; set; } = "user-dir-prefix/";
        // 有効期限を秒単位で指定します。
        public int ExpireTime { get; set; } = 3600;
        public class PolicyConfig
        {
            public string expiration { get; set; }
            public List<List<object>> conditions { get; set; }
        }
        public class PolicyToken
        {
            public string Accessid { get; set; }
            public string Policy { get; set; }
            public string Signature { get; set; }
            public string Dir { get; set; }
            public string Host { get; set; }
            public string Expire { get; set; }
        }
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            var app = builder.Build();

            builder.Logging.AddConsole();
            var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();

            app.UseStaticFiles(); 

            app.MapGet("/", async (context) =>
            {
                var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
                var htmlContent = await File.ReadAllTextAsync(filePath);
                await context.Response.WriteAsync(htmlContent);
                logger.LogInformation("GET request to root path");
            });

            app.MapGet("/get_post_signature_for_oss_upload", async (context) =>
            {
                var program = new Program(logger);
                var token = program.GetPolicyToken();

                logger.LogInformation($"Token: {token}");

                context.Response.ContentType = "application/json";
                await context.Response.WriteAsync(token);
            });

            app.Run();
        }

        public Program(ILogger<Program> logger)
        {
            _logger = logger;
        }

        private string ToUnixTime(DateTime dateTime)
        {
            return ((DateTimeOffset)dateTime).ToUnixTimeSeconds().ToString();
        }

        private string GetPolicyToken()
        {
            var expireDateTime = DateTime.Now.AddSeconds(ExpireTime);
            var config = new PolicyConfig
            {
                expiration = FormatIso8601Date(expireDateTime),
                conditions = new List<List<object>>()
            };
            config.conditions.Add(new List<object>
            {
                "content-length-range", 0, 1048576000
            });
            var policy = JsonConvert.SerializeObject(config);
            var policyBase64 = EncodeBase64("utf-8", policy);
            var signature = ComputeSignature(AccessKeySecret, policyBase64);
            var policyToken = new PolicyToken
            {
                Accessid = AccessKeyId,
                Host = Host,
                Policy = policyBase64,
                Signature = signature,
                Expire = ToUnixTime(expireDateTime),
                Dir = UploadDir
            };
            return JsonConvert.SerializeObject(policyToken);
        }

        private string FormatIso8601Date(DateTime dtime)
        {
            return dtime.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'",
                                    CultureInfo.CurrentCulture);
        }

        private string EncodeBase64(string codeType, string code)
        {
            string encode = "";
            byte[] bytes = Encoding.GetEncoding(codeType).GetBytes(code);
            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = code;
            }
            return encode;
        }

        private string ComputeSignature(string key, string data)
        {
            using (var algorithm = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
            {
                return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(data)));
            }
        }
    }
}

クライアントサイドのサンプルコード

次のサンプルコードは、PostObject の署名や PostPolicy などの情報を使用して Web クライアントから OSS にファイルをアップロードする方法を示しています:

const form = document.querySelector("form");
const fileInput = document.querySelector("#file");
form.addEventListener("submit", (event) => {
  event.preventDefault();
  const file = fileInput.files[0];
  const filename = fileInput.files[0].name;
  fetch("/get_post_signature_for_oss_upload", { method: "GET" })
    .then((response) => {
      if (!response.ok) {
        throw new Error("Failed to obtain the signature");
      }
      return response.json();
    })
    .then((data) => {
      const formData = new FormData();
      formData.append("name", filename);
      formData.append("policy", data.policy);
      formData.append("OSSAccessKeyId", data.ossAccessKeyId);
      formData.append("success_action_status", "200");
      formData.append("signature", data.signature);
      formData.append("key", data.dir + filename);
      formData.append("file", file);

      return fetch(data.host, { method: "POST", body: formData });
    })
    .then((response) => {
      if (response.ok) {
        console.log("Upload successful");
        alert("The file is uploaded");
      } else {
        console.log("Upload failed", response);
        alert("Upload failed. Please try again later.");
      }
    })
    .catch((error) => {
      console.error("An error occurred:", error);
    });
});

サーバーでの PutObject のための署名付き URL の生成

重要

フロントエンドでオプションのパラメータを含む署名付き URL を使用したい場合は、サーバーで署名付き URL を生成する際に設定した Content-Type が、フロントエンドで設定した Content-Type と同じであることを確認してください。そうでない場合、SignatureDoesNotMatch エラーが発生する可能性があります。詳細については、「Content-Type (MIME) の設定方法」をご参照ください。

次の図は、サーバーで生成された署名付き URL を使用して、クライアントに OSS へのファイルアップロードを許可するプロセスを示しています。

サンプルコード

以下のコードは、主要なコードスニペットです。完全なコードについては、サンプルプロジェクト presignedurl.zip をご参照ください。

サーバーサイドのサンプルコード

次のサンプルコードは、サーバーで署名付き URL を生成する方法を示しています:

Java

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.net.URL;
import java.util.Date;
import javax.annotation.PreDestroy;

@Configuration
public class OssConfig {

    /**
     * OSS エンドポイント (例: oss-cn-hangzhou.aliyuncs.com) を設定します。
     */
    private static final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";

    /**
     * ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を使用して accessKeyId を設定します。
     */
    @Value("${ALIBABA_CLOUD_ACCESS_KEY_ID}")
    private String accessKeyId;

    /**
     * ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を使用して accessKeySecret を設定します。
     */
    @Value("${ALIBABA_CLOUD_ACCESS_KEY_SECRET}")
    private String accessKeySecret;

    private OSS ossClient;


    @Bean
    public OSS getSssClient() {
        // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合、Region を cn-hangzhou に設定します。
        String region = "cn-hangzhou";
         // OSSClient インスタンスを作成します。
         // OSSClient インスタンスが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);        
        OSS ossClient = OSSClientBuilder.create()
        .endpoint(endpoint)
        .credentialsProvider(credentialsProvider)
        .clientConfiguration(clientBuilderConfiguration)
        .region(region)               
        .build();
        return ossClient;
    }

    @PreDestroy
    public void onDestroy() {
        ossClient.shutdown();
    }
}

@Controller
public class PresignedURLController {

    /**
     * <your-bucket> をバケット名に置き換えます。
     * OSS にアップロードするファイルのプレフィックスを指定します。
     * <your-object> をオブジェクトの完全なパス (例: exampleobject.txt) に置き換えます。完全なパスにバケット名を含めることはできません。
     * 有効期限をミリ秒単位で指定します。
     */
    private static final String BUCKET_NAME = "<your-bucket>";
    private static final String OBJECT_NAME = "<your-object>";
    private static final long EXPIRE_TIME = 3600 * 1000L;

    @Autowired
    private OSS ossClient;

    @GetMapping("/get_presigned_url_for_oss_upload")
    @ResponseBody
    public String generatePresignedURL() {

        try {
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BUCKET_NAME, OBJECT_NAME, HttpMethod.PUT);
            Date expiration = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            request.setExpiration(expiration);
            request.setContentType("image/png");
            URL signedUrl = ossClient.generatePresignedUrl(request);
            return signedUrl.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Node.js

const express = require("express");
const OSS = require("ali-oss");
const app = express();

app.get("/get_presigned_url_for_oss_upload", async (req, res) => {
 const client = new OSS({
   // 環境変数から AccessKey ID、AccessKey Secret、STS トークンの値を取得します。
   accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
   accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
   stsToken: process.env.ALIBABA_CLOUD_SECURITY_TOKEN,
   // yourBucketName をバケット名に設定します。
   bucket: 'yourBucket',
   region: 'yourRegion',
   authorizationV4: true,
  });

  return await client.signatureUrlV4('PUT', 3600, {
    // 実際に送信するリクエストヘッダーに基づいてリクエストヘッダーを設定します。
    headers: {},
  }, 'demo.pdf');
});

app.listen(8000, () => {
  console.log("http://127.0.0.1:8000");
});

Python

import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# 環境変数からアクセス認証情報を取得します。このサンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# エンドポイントに対応するリージョン (例: cn-hangzhou) を指定します。このパラメータは V4 署名に必須です。
region = "cn-hangzhou"

# examplebucket をバケット名に設定します。
bucket = oss2.Bucket(auth, endpoint, "examplebucket", region=region)

# 有効期限を 3,600 秒に指定します。最大有効期限は 32,400 秒です。
expire_time = 3600
# オブジェクトの完全なパス (例: exampledir/exampleobject.png) を指定します。完全なパスにバケット名を含めることはできません。
object_name = 'exampledir/exampleobject.png'

def generate_presigned_url():
    # ヘッダーを指定します。
    headers = dict()
    # Content-Type を指定します。
    headers['Content-Type'] = 'image/png'
    # ストレージクラスを指定します。
    # headers["x-oss-storage-class"] = "Standard"
    # 署名付き URL が生成される際、OSS はデフォルトでオブジェクトの完全なパス内のスラッシュ (/) をエスケープします。その結果、生成された署名付き URL は直接使用できません。
    # slash_safe を True に設定します。これにより、OSS はオブジェクトの完全なパス内のスラッシュ (/) をエスケープせず、生成された署名付き URL を直接使用できます。
    url = bucket.sign_url('PUT', object_name, expire_time, slash_safe=True, headers=headers)
    return url

Go

package main

import (
	"fmt"
	"net/http"
	"os"
        "log"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func getURL() string {
	// yourEndpoint をバケットのエンドポイントに設定します。たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。他のリージョンについては、実際のエンドポイントを指定してください。
	endpoint := "https://oss-cn-hangzhou.aliyuncs.com"
	// バケット名 (例: examplebucket) を指定します。
	bucketName := "examplebucket"
	// ファイルの完全なパス (例: exampledir/exampleobject.txt) を指定します。完全なパスにバケット名を含めることはできません。
	objectName := "exampledir/exampleobject.txt"
	// 環境変数が設定されているかどうかを確認します。
	if endpoint == "" || bucketName == "" {
		log.Fatal("Please set yourEndpoint and bucketName.")
	}
	// 環境変数からアクセス認証情報を取得します。このサンプルコードを実行する前に、ALIBABA_CLOUD_ACCESS_KEY_ID と ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		handleError(err)
	}
        clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("yourRegion"))
	// 署名バージョンを設定します。
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
        client, err := oss.New(endpoint, "", "", clientOptions...)
	
	if err != nil {
		fmt.Println("json err:", err)
	}
	bucket, err := client.Bucket(bucketName)
	if err != nil {
		fmt.Println("json err:", err)
	}
	options := []oss.Option{
		oss.ContentType("image/png"),
	}
	signedURL, err := bucket.SignURL(objectName, oss.HTTPPut, 60, options...)
	if err != nil {
		fmt.Println("json err:", err)
	}

	return signedURL
}

func handler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.ServeFile(w, r, "templates/index.html")
		return
	} else if r.URL.Path == "/get_presigned_url_for_oss_upload" {
		url := getURL()
		fmt.Fprintf(w, "%s", url)
		return
	}
	http.NotFound(w, r)
}
func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

Ruby

require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
require 'aliyun/oss'
include Aliyun::OSS

# public フォルダのパスを現在のディレクトリの templates フォルダに設定します。
set :public_folder, File.dirname(__FILE__) + '/templates'

# ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
$access_key_id = ENV['ALIBABA_CLOUD_ACCESS_KEY_ID']
# ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
$access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_KEY_SECRET']

# オブジェクトの完全なパス (例: exampledir/exampleobject.png) を指定します。完全なパスにバケット名を含めることはできません。
object_key = 'exampledir/exampleobject.png'

def get_presigned_url(client, object_key)
  # <YOUR-BUCKET> をバケット名に置き換えます。
  bucket = client.get_bucket('<YOUR-BUCKET>')
  # 署名付き URL を生成し、有効期間を 3,600 秒に指定します。最大有効期間は 32,400 秒です。
  bucket.object_url(object_key, 3600)
end

client = Aliyun::OSS::Client.new(
  # <YOUR-ENDPOINT> をバケットが配置されているリージョンのエンドポイントに置き換えます。たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
  endpoint: '<YOUR-ENDPOINT>',
  # 環境変数からアクセス認証情報を取得します。このサンプルコードを実行する前に、OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
  access_key_id: $access_key_id,
  access_key_secret: $access_key_secret
)


if ARGV.length == 1 
  $server_port = ARGV[0]
elsif ARGV.length == 2
  $server_ip = ARGV[0]
  $server_port = ARGV[1]
end

$server_ip = "0.0.0.0"
$server_port = 8000

puts "App server is running on: http://#{$server_ip}:#{$server_port}"

set :bind, $server_ip
set :port, $server_port

get '/get_presigned_url_for_oss_upload' do
  url = get_presigned_url(client, object_key.to_s)
  puts "Token: #{url}"
  url
end

get '/*' do
  puts "********************* GET "
  send_file File.join(settings.public_folder, 'index.html')
end

C#

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System.IO;
using System;
using Microsoft.Extensions.Logging;
using Aliyun.OSS;

namespace YourNamespace
{
    public class Program
    {
        private ILogger<Program> _logger;

        // ALIBABA_CLOUD_ACCESS_KEY_ID 環境変数を設定します。
        public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
        // ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境変数を設定します。
        public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        // <YOUR-ENDPOINT> をバケットが配置されているリージョンのエンドポイントに置き換えます。たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
        private string EndPoint { get; set; } = "<YOUR-ENDPOINT>";
        // <YOUR-BUCKET> をバケット名に置き換えます。
        private string BucketName { get; set; } = "<YOUR-BUCKET>";
        private string ObjectName { get; set; } = "exampledir/exampleobject2.png";

        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            var app = builder.Build();

            // ログを追加します。
            builder.Logging.AddConsole();
            var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();

            app.UseStaticFiles(); // 静的ファイルミドルウェアを有効にするためにこの行を追加します。

            app.MapGet("/", async (context) =>
            {
                var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
                var htmlContent = await File.ReadAllTextAsync(filePath);
                await context.Response.WriteAsync(htmlContent);

                // ログを出力します。
                logger.LogInformation("GET request to root path");
            });

            app.MapGet("/get_presigned_url_for_oss_upload", async (context) =>
            {
                var program = new Program(logger);
                var signedUrl = program.GetSignedUrl();

                logger.LogInformation($"SignedUrl: {signedUrl}"); // トークンの値を出力します。
                await context.Response.WriteAsync(signedUrl);
            });

            app.Run();
        }

        // コンストラクターで ILogger をインジェクトします。
        public Program(ILogger<Program> logger)
        {
            _logger = logger;
        }

        private string GetSignedUrl()
        {
            // OssClient インスタンスを作成します。
            var ossClient = new OssClient(EndPoint, AccessKeyId, AccessKeySecret);

            // 署名付き URL を生成します。
            var generatePresignedUriRequest = new GeneratePresignedUriRequest(BucketName, ObjectName, SignHttpMethod.Put)
            {
                Expiration = DateTime.Now.AddHours(1),
                ContentType = "image/png"
            };
            var signedUrl = ossClient.GeneratePresignedUri(generatePresignedUriRequest);

            return signedUrl.ToString();
        }
    }
}

クライアントサイドのサンプルコード

次のサンプルコードは、署名付き URL を使用して Web クライアントから OSS にファイルをアップロードする方法を示しています:

const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
  event.preventDefault();
  const fileInput = document.querySelector("#file");
  const file = fileInput.files[0];
  fetch("/get_presigned_url_for_oss_upload", { method: "GET" })
    .then((response) => {
      if (!response.ok) {
        throw new Error("Failed to obtain the presigned URL");
      }
      return response.text();
    })
    .then((url) => {
      const formData = new FormData();
      formData.append("file", file);
      fetch(url, {
        method: "PUT",
        headers: new Headers({
          "Content-Type": "image/png",
        }),
        body: file,
      }).then((response) => {
        if (!response.ok) {
          throw new Error("Failed to upload the file to OSS");
        }
        console.log(response);
        alert("The file is uploaded");
      });
    })
    .catch((error) => {
      console.error("An error occurred:", error);
      alert(error.message);
    });
});

関連ドキュメント

  • Security Token Service (STS) を使用した一時的なアクセス権限付与の完全なコードサンプルについては、「GitHub の例」をご参照ください。

  • 署名付き URL を使用した一時的なアクセス権限付与の完全なコードサンプルについては、「GitHub の例」をご参照ください。