All Products
Search
Document Center

Object Storage Service:Add signatures to requests, upload an object to OSS, and configure upload callbacks

Last Updated:Dec 12, 2025

Use the PostObject operation to upload objects directly from a web client to OSS. You can also configure upload callbacks. The signature generated by the server ensures secure transmission for direct uploads. You can also configure upload policies to restrict upload operations and meet your business requirements.

Solution overview

The following figure shows how to generate a signature on an application server and upload a file directly from a web client to OSS:

image

To add a signature to requests, upload an object to OSS, and configure upload callbacks, perform the following steps:

Note

In this process, temporary access credentials are used. This prevents the AccessKey pair of the application server from being leaked and ensures the security of the object during the upload process.

  1. Configure OSS: Create a bucket in the OSS console to store objects uploaded by users. Configure cross-origin resource sharing (CORS) rules for the bucket to allow cross-origin requests from web clients.

  2. Configure the server: Generate a signature by using access credentials and pre-configured upload policies such as the bucket name, directory path, and expiration time. This signature authorizes users to upload objects within a specific period of time.

  3. Configure the web client: Construct an HTML form and upload objects directly to OSS. OSS parses the upload callback settings of the client and sends a POST callback request to the application server.

Sample projects

Procedure

Step 1: Configure OSS

1. Create a bucket

Create an OSS bucket to store data that is uploaded by the web application from a browser.

  1. Log on to the OSS console.

  2. In the left-side navigation pane, click Buckets and then click Create Bucket.

  3. In the Create Bucket panel, select Quick Create and configure the following parameters.

    Parameter

    Example value

    Bucket Name

    web-direct-upload- callback

    Region

    China (Hangzhou)

  4. Click Create.

2. Configure CORS rules

Configure a CORS rule for the bucket that you created.

  1. Go to the Buckets page and click the name of the bucket.

  2. On the CORS page, click Create Rule.

  3. In the Create Rule panel, configure the CORS rule based on the following information.

    Parameter

    Example

    Origin

    *

    Allowed Methods

    POST, PUT, and GET

    Allowed Headers

    *

  1. Click OK.

Step 2: Configure the server

Note

If you already have a server, skip the preparations and go to 1. Configure user permissions.

Preparations: Create an ECS instance as a business server

Operation 1: Create an ECS instance

Go to the Custom Launch page and create or select the basic resources required to purchase an ECS instance based on the following information.

  1. Select a region and billing method

    1. Select a billing method based on your use case. In this topic, the pay-as-you-go billing method is selected because it is more flexible.

    2. Select a region based on your network latency requirements. In most cases, we recommend that you choose a region in close proximity to your users to achieve lower network latency and higher access speed. In this topic, China (Hangzhou) is selected.

      image

  1. Create a virtual private cloud (VPC) and a vSwitch

    When you create a VPC, select the region in which you want to create an ECS instance and plan CIDR blocks based on your business requirements. In this topic, a VPC and a vSwitch in the China (Hangzhou) region are created. After you create a VPC, go back to the Custom Launch tab of the instance buy page in the ECS console, refresh the VPC and vSwitch drop-down lists, and then select the VPC and vSwitch that you created.

    Note

    You can also create a vSwitch when you create the VPC.

    image

    image

    image

  1. Select an instance type and an image

    Select an instance type and an image. The operating system version included in the image is installed on the instance during instance creation. In this topic, the ecs.e-c1m1.large instance type is selected because it meets the test requirements and is cost-effective. The Alibaba Cloud Linux 3.2104 LTS 64-bit public image is selected.

    image

  1. Configure storage

    Configure a system disk and data disks for the ECS instance based on your business requirements. Since this demo project deploys a lightweight web application, a system disk alone suffices, and no data disks are configured.

    image

  1. Assign a public IP address

    To provide Internet connectivity to the ECS instance, select Assign Public IPv4 Address to assign a public IP address to the instance. You can also associate an elastic IP address (EIP) with the instance after the instance is created. For more information, see Associate an EIP with a cloud resource.

    Note
    • If you do not assign a public IP address to or associate an EIP with the ECS instance, you cannot access the instance over SSH or Remote Desktop Protocol (RDP) or test the web service that is deployed on the instance over the Internet.

    • In this topic, Pay-by-traffic (CDT) is selected as the billing method for network usage. In the pay-by-traffic billing method, you are charged based on the amount of data transferred over the Internet. For more information, see Public bandwidth billing.

    image

  1. Create a security group

    Create a security group for the ECS instance. A security group serves as a virtual firewall that can control inbound and outbound traffic for ECS instances. When you create a security group, open the following ports to allow access to the ECS instance:

    Open IPv4 Ports/Protocols: SSH (22), RDP (3389), HTTP (80), and HTTPS (443).

    Note
    • The Open IPv4 Ports/Protocols parameter specifies the ports that must be opened for the applications that run on the ECS instance.

    • By default, a rule that references 0.0.0.0/0 as a source address is created in the new security group. 0.0.0.0/0 represents all IP addresses. The rule allows access to the ECS instance from all IP addresses on the specified ports. After you create the instance, we recommend that you modify the rule to allow access to the instance from only specific IP addresses. For more information, see Modify a security group rule.

    image

  1. Create a key pair

    1. A key pair is a secure credential that is used to verify your identity when you log on to an ECS instance. After you create a key pair, you must download the private key for future use when you connect to the ECS instance. After you create a key pair, go back to the Custom Launch tab of the instance buy page, refresh the Key Pair drop-down list, and then select the key pair that you created.

    2. The root user has the highest permissions on the operating system. Using root as the logon username may lead to security risks. We recommend that you select ecs-user as the logon username.

      Note

      After you create a key pair, the private key is automatically downloaded. Check the download records of your browser and save the .pem private key file.

      image

  1. Create and view the ECS instance

    After you create or select the basic resources required for the ECS instance, click Create Order. In the message that appears, click Console to view the created ECS instance in the console. Record the following data for later use:

    • Instance ID: used to query the instance in the instance list.

    • Region: used to query the instance in the instance list.

    • Public IP address: used to verify the deployment of the web service on the ECS instance.

    imageimage

Operation 2: Connect to the ECS instance

  1. On the Instance page of the ECS console, find the created ECS instance based on the region and instance ID. Click Connect in the Actions column.image

  2. In the Remote connection dialog box, click Sign in now below Workbench.image

  3. In the Instance Login dialog box, set Connection Method to Terminal and Authentication to SSH Key Authentication. Enter or upload the private key file that you downloaded when you created the key pair, then Log In the ECS instance as the ecs-user user.

    Note

    The private key file is automatically downloaded to your computer when you create a key pair. Check the download records of your browser and find the .pem private key file.

  4. If the following page appears, you have logged on to the ECS instance.image

1. Configure user permissions

Note

To prevent local files from failing to be uploaded due to unauthorized operations after the deployment is complete, we recommend that you perform the following steps to create a RAM user and grant the required permissions to the RAM user.

Operation 1: Create a RAM user in Resource Access Management (RAM)

Create a RAM user and obtain the AccessKey pair of the RAM user. The AccessKey pair is a long-term access credential that is required to access and manage the application.

  1. Log on to the RAM console by using your Alibaba Cloud account or as an account administrator.

  2. In the left-side navigation pane, choose Identities > Users.

  3. Click Create User.

  4. Enter a Logon Name and a Display Name.

  5. In the Access Mode section, select Using permanent AccessKey to access, then click OK.

Important

You can obtain the AccessKey secret of a RAM user only when you create the RAM user. Keep the AccessKey secret secure to prevent credential leaks.

  1. Click Copy in the Actions column to save the AccessKey pair (AccessKey ID and AccessKey secret).

Operation 2: Grant the RAM user the permissions to call the AssumeRole operation in RAM

Grant the RAM user the permissions to call the AssumeRole operation of STS. This way, the RAM user can assume a RAM role to obtain STS tokens.

  1. In the left-side navigation pane, choose Identities > Users.

  2. On the Users page, find the RAM user and click Add Permissions in the Actions column.

  3. On the Grant Permission page, select the AliyunSTSAssumeRoleAccess system policy.

    Note

    The fixed permission that is required to call the AssumeRole operation of STS is AliyunSTSAssumeRoleAccess. This permission is not related to the permissions that are required to obtain temporary access credentials and use the temporary access credentials to send requests to OSS.

  4. Click OK.

Operation 3: Create a RAM role in RAM

Create a RAM role for your Alibaba Cloud account and obtain the Alibaba Cloud Resource Name (ARN) of the RAM role. The RAM user can assume the RAM role.

  1. In the left-side navigation pane, choose Identities > Roles.

  2. Click Create Role. Select Cloud Account for Principal Type.

  3. Select Current Account and click OK.

  4. Enter a role name and click OK.

  5. On the Basic Information page, click Copy and save the ARN of the RAM role.

Operation 4: Create upload file access policy in Resource Access Management

Create a custom policy based on the principle of least privilege to grant the RAM role the permissions to upload data only to a specific bucket.

  1. In the left-side navigation pane, choose Permissions > Policies.

  2. Click Create Policy.

  3. On the Create Policy page, click JSON. Replace <BucketName> in the following script with the name of the bucket that you created in the preparations, which is web-direct-upload.

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "oss:PutObject",
          "Resource": "acs:oss:*:*:<BucketName>/*"
        }
      ]
    }
  4. After you configure the policy, click OK.

  5. In the Create Policy dialog box, enter a Policy Name and click OK.

Operation 5: Grant permissions to the RAM role in RAM

Attach the custom policy to the RAM role. This way, the RAM role can provide the required permissions when the RAM role is assumed.

  1. In the left-side navigation pane, choose Identities > Roles.

  2. On the Roles page, find the RAM role and click Grant Permission in the Actions column.

  3. On the Grant Permission page, select Custom Policy and select the custom policy that you created.

  4. Click OK.

2. Obtain the temporary access credentials and calculate the signature on the application server

Note

We recommend that you configure sensitive information such as accessKeyId, accessKeySecret, and roleArn as environment variables to avoid explicit configuration in the code and reduce the risk of leaks.

You can add environment variables by using the following steps.

Linux operating system

  1. Run the following commands in the command-line interface to append environment variables to the ~/.bashrc file.

    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. Run the following command to apply the changes:

    source  ~/.bashrc
  3. Run the following commands to check whether the environment variables take effect:

    echo $OSS_ACCESS_KEY_ID
    echo $OSS_ACCESS_KEY_SECRET
    echo $OSS_STS_ROLE_ARN

macOS

  1. Run the following command in the terminal to view the default Shell type:

    echo $SHELL
  2. Perform operations based on the default Shell type.

    Zsh

    1. Run the following commands to append environment variables to the ~/.zshrc file.

      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. Run the following command to allow the changes to take effect:

      source ~/.zshrc
    3. Run the following commands to check whether the environment variables take effect:

      echo $OSS_ACCESS_KEY_ID
      echo $OSS_ACCESS_KEY_SECRET
      echo $OSS_STS_ROLE_ARN

    Bash

    1. Run the following commands to append environment variables to the ~/.bash_profile file.

      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. Run the following command to allow the changes to take effect:

      source ~/.bash_profile
    3. Run the following commands to check whether the environment variables take effect:

      echo $OSS_ACCESS_KEY_ID
      echo $OSS_ACCESS_KEY_SECRET
      echo $OSS_STS_ROLE_ARN

Windows

  1. Run the following commands in Command Prompt:

    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. Open a new Command Prompt window.

  3. Run the following commands to check whether the environment variables take effect in the new window:

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

You can refer to the following code to calculate POST Signature Version 4 (recommended) on the server. For more information about the policy form field, see Policy form fields.

Java

Add the following dependencies to the Maven project:

<!-- 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>

The following sample code provides an example on how to obtain temporary access credentials from STS, calculate the signature that you can use to upload an object, and configure an upload callback:

package com.aliyun.oss.web;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Controller
public class WebController {

    // The OSS bucket information. Replace the values with your actual information.
    String bucket = "examplebucket";
    String region = "cn-hangzhou";
    String host = "http://examplebucket.oss-cn-hangzhou.aliyuncs.com";
    // Specify the URL of the application server to which the upload callback request is sent. The URL must be a public domain name. This URL is used for communication between the application server and OSS. After you upload an object, OSS uses the URL to send upload information to the application server.
    String callbackUrl = "http://oss-demo.aliyuncs.com:23450/callback"; // Specify the address of the callback server that receives the callback request. Example: http://oss-demo.aliyuncs.com:23450/callback.
    // The prefix of the names of objects uploaded to OSS.
    String upload_dir = "dir";

    // The validity period of the temporary credentials. Unit: seconds.
    Long expire_time = 3600L;

    /**
     * The expiration time is calculated based on the specified validity period. Unit: seconds.
     * @param seconds: the validity period, in seconds.
     * @return: the time string in the ISO 8601 standard. Example: 2014-12-01T12:00:00.000Z.
     */
    public static String generateExpiration(long seconds) {
        // The current timestamp. Unit: seconds.
        long now = Instant.now().getEpochSecond();
        // The timestamp for the expiration time.
        long expirationTime = now + seconds;
        // Convert the timestamp into an Instant object and format it in the ISO 8601 format.
        Instant instant = Instant.ofEpochSecond(expirationTime);
        // Define the time zone as UTC.
        ZoneId zone = ZoneOffset.UTC;
        // Convert the Instant object into a ZonedDateTime object.
        ZonedDateTime zonedDateTime = instant.atZone(zone);
        // Define the datetime format. Example: 2023-12-03T13:00:00.000Z.
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        // Format the date and time.
        String formattedDate = zonedDateTime.format(formatter);
        // Output the result.
        return formattedDate;
    }
    // Initialize the STS client.
    public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
        // If the project code is leaked, the AccessKey pair may be leaked and security issues may occur in all resources that belong to your Alibaba Cloud account.
        // We recommend that you use STS, which is more secure.
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                // Required. Make sure that the OSS_ACCESS_KEY_ID environment variable is configured.
                .setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID"))
                // Required. Make sure that the OSS_ACCESS_KEY_SECRET environment variable is configured.
                .setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET"));
        // Specify the endpoint. For more information, visit https://api.aliyun.com/product/Sts
        config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
        return new com.aliyun.sts20150401.Client(config);
    }

    // Obtain a security token from STS.
    public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception {
        com.aliyun.sts20150401.Client client = WebController.createStsClient();
        com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
                // Make sure that the OSS_STS_ROLE_ARN environment variable is configured.
                .setRoleArn(System.getenv("OSS_STS_ROLE_ARN"))
                .setRoleSessionName("yourRoleSessionName");// Specify a custom session name.
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        try {
            // Write your own code to display the response of the API operation if necessary.
            AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
            // The AccessKey ID, AccessKey secret, and STS token that are required for subsequent operations are included in credentials.
            return response.body.credentials;
        } catch (TeaException error) {
            // Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided only for reference.
            // Print error messages.
            System.out.println(error.getMessage());
            // The URL for troubleshooting.
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        } 
        // Return a default error response object to avoid returning 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;
        
        // Obtain the current date in the x-oss-credential header. The value is in the yyyyMMdd format.
        ZonedDateTime today = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String date = today.format(formatter);
        
        // Obtain the x-oss-date header.
        ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
        String x_oss_date = now.format(formatter2);

        // Step 1: Create a policy.
        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); // Replace the value with your 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);

        // Step 2: Create a string to sign.
        String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));

        // Step 3: Calculate the signing key.
        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");

        // Step 4: Calculate the signature.
        byte[] result = hmacsha256(signingKey, stringToSign);
        String signature = BinaryUtil.toHex(result);

        // Step 5: Configure a callback.
        JSONObject jasonCallback = new JSONObject();
        jasonCallback.put("callbackUrl", callbackUrl);
        jasonCallback.put("callbackBody","filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
        jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
        String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());

        Map<String, String> response = new HashMap<>();
        // Add data to the Map object.
        response.put("version", "OSS4-HMAC-SHA256");
        response.put("policy", stringToSign);
        response.put("x_oss_credential", x_oss_credential);
        response.put("x_oss_date", x_oss_date);
        response.put("signature", signature);
        response.put("security_token", securitytoken);
        response.put("dir", upload_dir);
        response.put("host", host);
        response.put("callback", base64CallbackBody);
        // Return the ResponseEntity class that includes the 200 OK status code to the web client. Then, the client can perform the PostObject operation.
        return ResponseEntity.ok(response);
    }
    public static byte[] hmacsha256(byte[] key, String data) {
        try {
            // Initialize the HMAC key specifications, set the algorithm to HMAC-SHA256, and use the provided key.
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");

            // Obtain a Mac instance and use the getInstance method to set the algorithm to HMAC-SHA256.
            Mac mac = Mac.getInstance("HmacSHA256");
            // Use the key to initialize the Mac instance.
            mac.init(secretKeySpec);

            // Calculate the HMAC value. Use the doFinal method to receive the data to be calculated and return the calculation results in arrays.
            byte[] hmacBytes = mac.doFinal(data.getBytes());

            return hmacBytes;
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }
}

Python

Run the following command to install dependencies:

pip install flask
pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials

The following sample code provides an example on how to obtain temporary access credentials from STS, calculate the signature that you can use to upload an object, and configure an upload callback:

from flask import Flask, render_template, jsonify, request
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
import os
import json
import base64
import hmac
import datetime
import time
import hashlib

import oss2

app = Flask(__name__)

# Configure the OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, and OSS_STS_ROLE_ARN environment variables.
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')

# Specify a session name.
role_session_name = 'yourRoleSessionName'

# Replace the values with the actual bucket name, region ID, and host endpoint.
bucket = 'examplebucket'
region_id = 'cn-hangzhou'
host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'

# Specify the validity period of the temporary access credentials. Unit: seconds.
expire_time = 3600

# Specify the prefix in the name of the object in OSS.
upload_dir = 'dir'

def hmacsha256(key, data):
    """
    The function calculates an HMAC-SHA256 value.
    :param key: The key used to calculate the hash value. The key is of the byte type.
    :param data: The data whose hash value you want to calculate. The data is of the string type.
    :return: The calculated HMAC-SHA256 value. The value is of the byte type.
    """
    try:
        mac = hmac.new(key, data.encode(), hashlib.sha256)
        hmacBytes = mac.digest()
        return hmacBytes
    except Exception as e:
        raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")

@app.route("/")
def hello_world():
    return render_template('index.html')

@app.route('/get_post_signature_for_oss_upload', methods=['GET'])
def generate_upload_params():
    # Initialize the configuration.
    config = Config(
        region_id=region_id,
        access_key_id=access_key_id,
        access_key_secret=access_key_secret
    )

    # Create an STSClient instance and obtain temporary access credentials.
    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()

    # Use the temporary access credentials returned by STS.
    temp_access_key_id = token_data['AccessKeyId']
    temp_access_key_secret = token_data['AccessKeySecret']
    security_token = token_data['SecurityToken']

    now = int(time.time())
    # Convert the timestamp to a datetime object.
    dt_obj = datetime.datetime.utcfromtimestamp(now)
    # Set the expiration time to 3 hours later than the current time.
    dt_obj_plus_3h = dt_obj + datetime.timedelta(hours=3)

    # Specify the time of the request.
    dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
    # The request date.
    dt_obj_2 = dt_obj.strftime('%Y%m%d')
    # The expiration time of the request.
    expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
    # Define the function used to encode the callback parameter in Base64.
    def encode_callback(callback_params):
        cb_str = json.dumps(callback_params).strip()
        return oss2.compat.to_string(base64.b64encode(oss2.compat.to_bytes(cb_str)))
    
    # Create callback configurations and encode it in Base64.
    callback_config = {
        "callbackUrl": "http://oss-demo.aliyuncs.com:23450/callback",  # Specify the address of the local callback server.
        "callbackBody": "bucket=${bucket}&object=${object}&etag=${etag}&size=${size}",
        "callbackBodyType": "application/x-www-form-urlencoded"
    }
    encoded_callback = encode_callback(callback_config)
    # Create a policy and generate a signature.
    policy = {
        "expiration": expiration_time,
        "conditions": [
            ["eq", "$success_action_status", "200"],
            {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
            {"x-oss-credential": f"{temp_access_key_id}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request"},
            {"x-oss-security-token": security_token},
            {"x-oss-date": dt_obj_1},
        ]
    }
    policy_str = json.dumps(policy).strip()

    # Step 2: Create a string to sign.
    stringToSign = base64.b64encode(policy_str.encode()).decode()

    # Step 3: Calculate the signing key.
    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")

    # Step 4: Calculate the signature.
    result = hmacsha256(signingKey, stringToSign)
    signature = result.hex()

    # The response data.
    response_data = {
        'policy': stringToSign,  # The form field.
        'x_oss_signature_version': "OSS4-HMAC-SHA256",  # The signature version and the algorithm used to calculate the signature. Set the value to OSS4-HMAC-SHA256.
        'x_oss_credential': f"{temp_access_key_id}/{dt_obj_2}/cn-hangzhou/oss/aliyun_v4_request",  # The parameter set used to specify information about the derived key.
        'x_oss_date': dt_obj_1,  # The request time.
        'signature': signature,  # The signature description.
        'host': host,
        'dir': upload_dir,
        'security_token': security_token,  # The security token.
        'callback': encoded_callback   # Return the Base64-encoded callback configurations.
    }

    return jsonify(response_data)


if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8000)  # If you need to listen on other addresses such as 0.0.0.0, you need to add an authentication mechanism on the server.

Node.js

Run the following command to install dependencies:

npm install ali-oss
npm install @alicloud/credentials
npm install express

The following sample code provides an example on how to obtain temporary access credentials from STS, calculate the signature that you can use to upload an object, and configure an upload callback:

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; // Specify the port number.

// Specify the directory in which the static file is stored.
app.use(express.static('templates'));

const GenerateSignature = async () => {
    // Initialize the STS client instance.
    let sts = new STS({
        accessKeyId: process.env.OSS_ACCESS_KEY_ID,  // Obtain the AccessKey ID of the RAM user from environment variables.
        accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET // Obtain the AccessKey secret of the RAM user from environment variables.
    });

    // Call the assumeRole operation to obtain an STS token.
    const result = await sts.assumeRole(process.env.env.OSS_STS_ROLE_ARN, '', '3600', 'yourRoleSessionName'); // Obtain the ARN of the RAM role from the environment variable, set the validity period of the temporary access credentials to 3600 seconds, and set the role session name to yourRoleSessionName.

    // Extract the value of the AccessKeyId, AccessKeySecret, and SecurityToken parameters from the temporary access credentials.
    const accessKeyId = result.credentials.AccessKeyId;
    const accessKeySecret = result.credentials.AccessKeySecret;
    const securityToken = result.credentials.SecurityToken;

    // Initialize the OSS client instance.
    const client = new OSS({
        bucket: 'examplebucket', // Replace examplebucket with the actual bucket name.
        region: 'cn-hangzhou', // Replace cn-hangzhou with the region in which the bucket is located.
        accessKeyId,
        accessKeySecret,
        stsToken: securityToken,
        refreshSTSTokenInterval: 0,
        refreshSTSToken: async () => {
            const { accessKeyId, accessKeySecret, securityToken } = await client.getCredential();
            return { accessKeyId, accessKeySecret, stsToken: securityToken };
        },
    });

    // Create a Map to store form fields.
    const formData = new Map();

    // Set the signature expiration time to 10 minutes later than the current time. 
    const date = new Date();
    const expirationDate = new Date(date);
    expirationDate.setMinutes(date.getMinutes() + 10);

    // Format the date as a UTC time string that conforms to the ISO 8601 standard.
    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);
    // Specify the URL of the application server to which the upload callback request is sent. The URL must be a public domain name. This URL is used for communication between the application server and OSS. After you upload an object, OSS uses the URL to send information about the uploaded object to the application server. For example, you can set callbackUrl to https://oss-demo.aliyuncs.com:23450.

    // Generate x-oss-credential and specify the form data.
    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');
  
    // Create a policy.
    // In the following policy form field, only required fields are specified.
    const policy = {
        expiration: expirationDate.toISOString(),
        conditions: [
            { 'bucket': 'examplebucket' }, // Replace examplebucket with the actual bucket name.
            { 'x-oss-credential': credential },
            { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
            { 'x-oss-date': formattedDate },
        ],
    };

    // If a security token exists, add it to the policy and form data.
    if (client.options.stsToken) {
        policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
        formData.set('security_token', client.options.stsToken);
    }

    // Generate a signature and specify the form data.
    const signature = client.signPostObjectPolicyV4(policy, date);
    formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
    formData.set('signature', signature);
    const callback = {
      callbackUrl: 'http://oss-demo.aliyuncs.com:23450/callback',// Specify the address of the callback server that receives the callback request. Example: http://oss-demo.aliyuncs.com:23450/callback.
      callbackBody:// Specify the content that you want the callback request to contain such as the ETag and the mimeType of the uploaded object.
      "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
      callbackBodyType: "application/x-www-form-urlencoded",// Specify the content type of the callback.    
    };
    // Return the form data.
    return {
        host: `http://${client.options.bucket}.oss-${client.options.region}.aliyuncs.com`, 
        policy: Buffer.from(policy2Str(policy), 'utf8').toString('base64'),
        x_oss_signature_version: 'OSS4-HMAC-SHA256',
        x_oss_credential: credential,
        x_oss_date: formattedDate,
        signature: signature,
        dir: 'user-dir', // Specify the prefix contained in the name of the object that you want to upload to OSS.
        callback: Buffer.from(JSON.stringify(callback)).toString("base64"),// The Base64-encoded JSON by using Buffer.from.
        security_token: client.options.stsToken
    };
};

app.get('/get_post_signature_for_oss_upload', async (req, res) => {
    try {
        const result = await GenerateSignature();
        res.json(result); // Return the generated signature data.
    } catch (error) {
        console.error('Error generating signature:', error);
        res.status(500).send('Error generating signature');
    }
});

app.listen(PORT, () => {
    console.log(`Server is running on http://127.0.0.1:${PORT}`); //If you need to listen on other addresses such as 0.0.0.0, you need to add an authentication mechanism on the server.
});

Go

Run the following command to install dependencies:

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

The following sample code provides an example on how to obtain temporary access credentials from STS, calculate the signature that you can use to upload an object, and configure an upload callback:

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

// Define the global variables.
var (
	region     string
	bucketName string
	product    = "oss"
)

// Use the PolicyToken structure to store the generated form data.
type PolicyToken struct {
	Policy           string `json:"policy"`
	SecurityToken    string `json:"security_token"`
	SignatureVersion string `json:"x_oss_signature_version"`
	Credential       string `json:"x_oss_credential"`
	Date             string `json:"x_oss_date"`
	Signature        string `json:"signature"`
	Host             string `json:"host"` 
	Dir              string `json:"dir"` 
    Callback         string `json:"callback"`
}

type CallbackParam struct{
    CallbackUrl string `json:"callbackUrl"`
    CallbackBody string `json:"callbackBody"`
    CallbackBodyType string `json:"callbackBodyType"`
}

func main() {
	// Specify the default IP and port strings.
	strIPPort := ":8080"
	if len(os.Args) == 3 {
		strIPPort = fmt.Sprintf("%s:%s", os.Args[1], os.Args[2])
	} else if len(os.Args) != 1 {
		fmt.Println("Usage   : go run test1.go                ")
		fmt.Println("Usage   : go run test1.go ip port        ")
		fmt.Println("Example : go run test1.go 11.22.**.** 80 ")
		fmt.Println("Example : go run test1.go 0.0.0.0 8080 ")
		fmt.Println("")
		os.Exit(0)
	}
	// Display the IP address and port of the server.
	fmt.Printf("server is running on %s \n", strIPPort)
	// Register the function that processes the root path requests.
	http.HandleFunc("/", handlerRequest)
	// Register the function that processes the requests initiated to obtain the signature.
	http.HandleFunc("/get_post_signature_for_oss_upload", handleGetPostSignature)
	// Start the HTTP server.
	err := http.ListenAndServe(strIPPort, nil)
	if err != nil {
		strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
		panic(strError)
	}
}

// Use the handlerRequest function to process the root path requests.
func handlerRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		http.ServeFile(w, r, "templates/index.html")
		return
	}
	http.NotFound(w, r)
}

// Use the handleGetPostSignature function to process the requests initiated to obtain the signature.
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", "*") // Allow cross-origin requests.
		w.Write([]byte(response))
		return
	}
	http.NotFound(w, r)
}

// Use the getPolicyToken function to generate the signature and access credentials required to upload an object.
func getPolicyToken() string {
	// Specify the region in which the bucket is located.
	region = "cn-hangzhou"
	// Specify the bucket name.
	bucketName = "examplebucket"
	// Specify the URL to which the datahttps://%s.oss-%s.aliyuncs.com", bucketName, region)
	// Specify the directory to which you want to upload the object.
	dir := "user-dir"
    // Specify the URL of the application server to which an upload callback request is sent. Replace the IP address and port number with the actual values.
    callbackUrl := "http://oss-demo.aliyuncs.com:23450/callback";

	config := new(credentials.Config).
		SetType("ram_role_arn").
		SetAccessKeyId(os.Getenv("OSS_ACCESS_KEY_ID")).
		SetAccessKeySecret(os.Getenv("OSS_ACCESS_KEY_SECRET")).
		SetRoleArn(os.Getenv("OSS_STS_ROLE_ARN")).
		SetRoleSessionName("Role_Session_Name").
		SetPolicy("").
		SetRoleSessionExpiration(3600)

	// Create a credential provider based on the configurations.
	provider, err := credentials.NewCredential(config)
	if err != nil {
		log.Fatalf("NewCredential fail, err:%v", err)
	}

	// Obtain access credentials from the credential provider.
	cred, err := provider.GetCredential()
	if err != nil {
		log.Fatalf("GetCredential fail, err:%v", err)
	}

	// Create a policy.
	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},
		},
	}

	// Convert the format of the policy to JSON.
	policy, err := json.Marshal(policyMap)
	if err != nil {
		log.Fatalf("json.Marshal fail, err:%v", err)
	}


    // Create a string-to-sign.
    stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))

    hmacHash := func() hash.Hash { return sha256.New() }
        // Create a signing key.
    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)

    // Generate a signature.
    h := hmac.New(hmacHash, h4Key)
    io.WriteString(h, stringToSign)
    signature := hex.EncodeToString(h.Sum(nil))

    var callbackParam CallbackParam
    callbackParam.CallbackUrl = callbackUrl
    callbackParam.CallbackBody = "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}"
    callbackParam.CallbackBodyType = "application/x-www-form-urlencoded"
    callback_str,err:=json.Marshal(callbackParam)
    if err != nil {
        fmt.Println("callback json err:", err)
    }
    callbackBase64 := base64.StdEncoding.EncodeToString(callback_str)
	// Create content that will be returned to the frontend form.
	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, // Return the bucket to which the object is uploaded.
		Dir:              dir,  // The directory to which the data is uploaded.
        Callback:         callbackBase64, // Return the upload callback parameters.
	}

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

PHP

Run the following command to install dependencies:

composer install

The following sample code provides an example on how to obtain temporary access credentials from STS, calculate the signature that you can use to upload an object, and configure an upload callback:

<?php

// Use Alibaba Cloud SDKs.
require_once __DIR__ . '/vendor/autoload.php';

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;

// Disable error displaying.
ini_set('display_errors', '0');


$bucket = 'examplebucket'; // Replace the value with your actual bucket name.
$region_id = 'cn-hangzhou'; // Replace the value with the region in which your bucket is located.
$host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'; // Replace the value with the URL of your bucket.
$expire_time = 3600; // The expiration time. Unit: seconds.
$upload_dir = 'user-dir'; // The prefix contained in the names of the objects that you upload.
// Specify the URL of the application server to which an upload callback request is sent. Replace the IP address and port number with the actual values.
$callbackUrl = 'http://oss-demo.aliyuncs.com:23450/callback';
// Calculate the HMAC-SHA256 value.
function hmacsha256($key, $data) {
    return hash_hmac('sha256', $data, $key, true);
}

// Process the requests initiated to obtain signatures.
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();
    // Create a request to obtain temporary access credentials from STS.
    $request = Sts::v20150401()->assumeRole();
    // Initiate the STS request and obtain the result.
    // Replace <YOUR_ROLE_SESSION_NAME> with a custom session name, such as oss-role-session.
    // Replace <YOUR_ROLE_ARN> with the ARN of the RAM role that has the permissions to upload objects to the specified bucket.
    $result = $request
        ->withRoleSessionName('oss-role-session')
        ->withDurationSeconds(3600)
        ->withRoleArn(getenv('OSS_STS_ROLE_ARN')) // Replace OSS_STS_ROLE_ARN with the ARN of the RAM role.
        ->request();
    // Obtain the credential information in the response to the STS request.
    $tokenData = $result->get('Credentials');
    // Construct JSON data from the returned result.
    $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));

    // Create a policy.
    $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);

    // Create a string to sign.
    $stringToSign = base64_encode($policyStr);

    // Calculate the signing key.
    $dateKey = hmacsha256(('aliyun_v4' . $tempAccessKeySecret), $dtObj1);
    $dateRegionKey = hmacsha256($dateKey, 'cn-hangzhou');
    $dateRegionServiceKey = hmacsha256($dateRegionKey, 'oss');
    $signingKey = hmacsha256($dateRegionServiceKey, 'aliyun_v4_request');

    // Calculate the signature.
    $result = hmacsha256($signingKey, $stringToSign);
    $signature = bin2hex($result);
    
    $callback_param = array(
    'callbackUrl' => $callbackUrl,
    'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
    'callbackBodyType' => "application/x-www-form-urlencoded"
    );
    $callback_string = json_encode($callback_param);

    $base64_callback_body = base64_encode($callback_string);

    // Return the signature data.
    $responseData = [
        'policy' => $stringToSign,
        'x_oss_signature_version' => "OSS4-HMAC-SHA256",
        'x_oss_credential' => "{$tempAccessKeyId}/{$dtObj1}/cn-hangzhou/oss/aliyun_v4_request",
        'x_oss_date' => $dtObj,
        'signature' => $signature,
        'host' => $host,
        'dir' => $upload_dir,
        'security_token' => $securityToken,
        'callback' => $base64_callback_body,
    ];

    header('Content-Type: application/json');
    echo json_encode($responseData);
    exit;
}

// Specify the homepage route.
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/') {
    echo file_get_contents(__DIR__ . '/public/index.html');
    exit;
}

// Specify other routes.
http_response_code(404);
echo json_encode(['message' => 'Not Found']);
exit;
?>

The Callback parameter is a Base64-encoded string that contains multiple fields in the JSON format. To construct a callback parameter, you must specify the URL (callbackUrl) of the server to which the callback request is sent and the content (callbackBody) of the callback request.

{"callbackUrl":"http://oss-demo.aliyuncs.com:23450/callback",
"callbackBody":"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}",
"callbackBodyType":"application/x-www-form-urlencoded"}

Parameter

Description

callbackUrl

The URL of the application server to which OSS sends the request.

callbackBody

The content that OSS sends to the application server. If you upload a non-image object, the content can be the object name, size, and type. If you upload an image, you can specify the image height and width.

callbackBodyType

The content type of the request.

Valid values:

  • application/x-www-form-urlencoded (default value)

  • application/json

Note

The preceding example shows only how to configure a callback. You can modify the server code to configure a callback based on your requirements. For more information, see Callback.

Step 3: Configure the web client

Construct and submit a form upload request on the web client

After the web client receives the required information from the application server, you can use the information to construct a request to create an HTML form. The request is directly sent to OSS for file upload.

Example response received by the web client

The following information is returned to the web client from the application server:

{
    "dir": "user-dirs",
    "host": "http://examplebucket.oss-cn-hangzhou.aliyuncs.com",
    "policy": "eyJl****",
    "security_token": "CAIS****",
    "signature": "9103****",
    "x_oss_credential": "STS.NSpW****/20241127/cn-hangzhou/oss/aliyun_v4_request",
    "x_oss_date": "20241127T060941Z",
    "x_oss_signature_version": "OSS4-HMAC-SHA256",
    "callback":"eyJjYWxsYmFja1VybCI6Imh0dHA6Ly9vc3MtZGVtby5hbGl5dW5jcy5jb206MjM0NTAiLAoiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JHtvYmplY3R9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZoZWlnaHQ9JHtpbWFnZUluZm8uaGVpZ2h0fSZ3aWR0aD0ke2ltYWdlSW5mby53aWR0aH0iLAoiY2FsbGJhY2tCb2R5VHlwZSI6ImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCJ9"
}

The following table describes the fields that are included in the body.

Field

Description

dir

Restrict the file prefixes that you can upload.

host

The domain name of the bucket.

policy

The policy for form upload. For more information, see Post Policy.

security_token

The security token that is obtained from STS.

signature

The signature string of the policy. For more information, see Post Signature.

x_oss_credential

The parameter set used to specify the derived key.

x_oss_date

The time of the request, which follows the ISO 8601 standard for date and time formats. Example: 20231203T121212Z.

x_oss_signature_version

The signature version and the algorithm used to calculate the signature. Set the value to OSS4-HMAC-SHA256.

callback

The callback content.

  • The form request contains file content and parameters returned by the server.

  • The web client can directly communicate with OSS and upload files by using the form request.

Note
  • Except for the file form field, the size of all other form fields including key cannot exceed 8 KB.

  • By default, an existing object that has the same name as the object that you want to upload is overwritten. If you do not want to overwrite the existing object, include the x-oss-forbid-overwrite header in the upload request and set the x-oss-forbid-overwrite header to true. This way, if you upload an object whose name is the same as an existing object, the upload fails and OSS returns the FileAlreadyExists error code.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Generate a signature on the server to upload files to OSS</title>
</head>
<body>
<div class="container">
    <form>
        <div class="mb-3">
            <label for="file" class="form-label">Select the file:</label>
            <input type="file" class="form-control" id="file" name="file" required />
        </div>
        <button type="submit" class="btn btn-primary">Upload</button>
    </form>
    <div id="callback-info" class="mt-3" style="display: none;">
        <h4>Callback information:</h4>
        <pre id="callback-content"></pre>
    </div>
</div>

<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
    const form = document.querySelector("form");
    const fileInput = document.querySelector("#file");
    const callbackInfo = document.querySelector("#callback-info");
    const callbackContent = document.querySelector("#callback-content");

    form.addEventListener("submit", (event) => {
        event.preventDefault();

        const file = fileInput.files[0];

        if (!file) {
            alert('Select a file to upload.');
            return;
        }

        const filename = file.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) => {
                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); // The file name.
                formData.append("x-oss-security-token", data.security_token);
                formData.append("callback", data.callback); // Specify callback parameters.
                formData.append("file", file); // The form field "file" must be the last one.

                return fetch(data.host, { 
                    method: "POST",
                    body: formData
                });
            })
            .then((response) => {
                if (response.ok) {
                    console.log("Uploaded");
                    alert("File uploaded");
                    return response.json(); // Parse the callback information.
                } else {
                    console.log("Upload failed with the following response:", response);
                    alert("Failed to upload the object. Try to re-upload the object");
                }
            })
            .then((callbackData) => {
                if (callbackData) {
                    callbackContent.textContent = JSON.stringify(callbackData, null, 2);
                    callbackInfo.style.display = "block";
                }
            })
            .catch((error) => {
                console.error("An error occurred:", error);
            });
    });
});
</script>
</body>
</html>
  • The HTML form contains a file input field and a Submit button. You can select a file to upload and submit the form.

  • When you submit the form, the default form submission is blocked by using JavaScript code, and the signature information required for the upload is obtained from the server by using an Asynchronous JavaScript and XML (AJAX) request.

  • After the signature information is obtained, a FormData object that contains all required form fields is constructed.

  • The POST request is sent to the URL of the OSS service by using the fetch method to upload the file.

If a file is uploaded, the "File uploaded" message is displayed. If a file fails to be uploaded, an error message is displayed. The corresponding callback information is returned on the frontend page.

Verification

After you complete the deployment, you can access the server address to use the web client signature upload feature.

  1. Access the server address in your browser, click the Select File button, select a file, and then upload the file.

  2. On the Buckets page, find the bucket that stores the files uploaded by users and check whether the files are uploaded.

Clean up resources

To build the web application, you created an ECS instance, an OSS bucket, a RAM user, and a RAM role. After you verify the solution, you can perform the following operations to release the resources. This way, you can avoid unnecessary fees or security risks.

Release the ECS instance

If you no longer need the ECS instance that you created, you can release it. After the ECS instance is released, billing for the instance stops, and data of the instance is lost and cannot be restored. To release the ECS instance, perform the following steps:

  1. Go back to the Instance page of the ECS console, find the ECS instance based on the region and instance ID, and click the image icon in the Actions column.

  2. Select Release.image

  3. After you confirm that the instance is correct, select Release Now and click Next.

  4. Confirm the associated resources that are about to be released, understand the relevant risks, then click OK to release the ECS instance.

Note
  • When the ECS instance is released, the system disk of the instance is released. If a public IP address was assigned to the instance, the IP address is also released.

  • When the ECS instance is released, the associated security group, vSwitch, and VPC are not released. You are not charged for the security group, vSwitch, or VPC. You can retain or release them based on your business requirements.

  • If an EIP is associated with the ECS instance, the EIP is retained when the instance is released. You are charged for the EIP. You can retain or release the EIP based on your business requirements.

Delete the bucket

  1. Log on to the OSS console.

  2. Click Buckets, and then click the name of the bucket.

  3. Delete all objects in the bucket.

  4. In the left-side navigation pane, click Delete Bucket, and then follow the instructions to delete the bucket.

Delete the RAM user

  1. Log on to the RAM console as a RAM administrator.

  2. In the left-side navigation pane, choose Identities > Users.

  3. On the Users page, click Delete in the Actions column.

    You can also select multiple RAM users and click Delete User below the user list to move multiple RAM users to the recycle bin at a time.

  4. In the Delete User dialog box, carefully read the impact of the deletion, enter the name of the RAM user, and then click Move To Recycle Bin.

Delete the RAM role

  1. Log on to the RAM console as a RAM administrator.

  2. In the left-side navigation pane, choose Identities > Roles.

  3. On the Roles page, click Delete Role in the Actions column.

  4. In the Delete Role dialog box, enter the name of the RAM role and click Delete Role.

    Note

    If a policy is attached to the RAM role, the policy is detached when you delete the RAM role.

FAQ

How do I upload multiple objects to OSS at a time?

The service does not support API operations for uploading multiple objects to OSS at a time. If you want to upload multiple objects to OSS at a time, you can repeatedly perform the steps for uploading a single object.

Can I specify the headers of callback requests when I obtain signature information from the server and configure upload callbacks?

No, you cannot specify custom callback parameters, that is, the body of the callback requests. However, you cannot specify the headers that are included in OSS callback requests to the callback URLs.