You can call the PostObject operation to upload an object from web clients to Object Storage Service (OSS) and configure upload callbacks. In this case, you can use the signature generated on the application server to ensure the security of the object during the upload process. You can also configure an upload policy to meet your business requirements.
Workflow
The following figure shows how to generate a signature on an application server and upload an object from a web client to OSS.
To add a signature to requests, upload an object to OSS, and configure upload callbacks, perform the following steps:
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.
Configure OSS: In the OSS console, create a bucket to store uploaded objects. Then, configure a cross-origin resource sharing (CORS) rule for the bucket to allow cross-origin requests from the application server.
Configure the application server: Use the temporary access credentials and the upload policy preset on the application server to generate a signature and authorize the user to upload an object within a specific period of time. The preset upload policy includes information such as the bucket name, directory path, and expiration time. The application server verifies the signature based on the
authorization
header included in the message that is sent by OSS. If the verification is successful, the application server returns the following message in the JSON format to OSS:Configure the web client: Create an HTML form and use the form to submit the signature and upload the object to OSS. OSS parses the upload callback configurations of the client and sends a POST callback request to the application server.
Demo projects
For information about the demo project in Java, see server-signed-direct-upload-callback-java.zip.
For information about the demo project in Python, see server-signed-direct-upload-callback-python.zip.
For information about the demo project in Go, see server-signed-direct-upload- callback-go.zip
For information about the demo project in Node.js, see server-signed-direct-upload-callback-nodejs.zip.
For information about the demo project in PHP, see server-signed-direct-upload-callback-php.zip.
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.
Log on to the OSS console.
In the left-side navigation pane, click Buckets. On the Buckets page, click Create Bucket.
In the Create Bucket panel, configure the parameters. The following table describes the parameters.
Parameter
Example
Bucket Name
web-direct-upload- callback
Region
China (Hangzhou)
Click Create.
2. Configure a CORS rule
Configure a CORS rule for the bucket that you created.
On the Buckets page, click the name of the bucket.
In the left-side navigation tree of the page that appears, choose Content Security > CORS. On the CORS page, click Create Rule.
In the Create Rule panel, configure the parameters. The following table describes the parameters.
Parameter
Example
Source
*
Allowed Methods
POST, PUT, and GET
Allowed Headers
*
Click OK.
Step 2: Configure the application server
In actual deployment, if you have your own application server, you do not need to perform operations in the "Preparations: Create an ECS instance as the application server" section and are redirected to 1. Configure user permissions.
Preparations: Create an ECS instance as the application server
Operation 1: Create an ECS instance
Go to the Custom Launch tab of the instance buy page in the Elastic Compute Service (ECS) console. Then, create or select the basic resources required by the ECS instance based on the following instructions.
Select a region and a billing method
Select a billing method based on your business requirements. In this example, the pay-as-you-go billing method is selected. This billing method allows you to perform more flexible operations compared with other billing methods.
Select a region based on the network latency requirements of your business. To achieve low network latency and high access speed, we recommend that you select a region in close proximity to your users. In this example, the China (Hangzhou) region is selected.
Create a VPC and a vSwitch
When you create a virtual private cloud (VPC), select the region in which you created the ECS instance and plan CIDR blocks based on your business requirements. In this example, a VPC and a vSwitch are created in the China (Hangzhou) region. 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 the vSwitch that you created.
NoteYou can also create a vSwitch when you create the VPC.
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 when you create the instance. In this example, the cost-effective
ecs.e-c1m1.large
instance type and theAlibaba Cloud Linux 3.2104 LTS 64-bit
public image are selected.
Select storage
Configure a system disk and data disks for the ECS instance based on your business requirements. This topic describes how to set up a simple web service on the ECS instance, which requires only a system disk to store the operating system of the instance.
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. Alternatively, you can also associate an elastic IP address (EIP) with the ECS instance after you create the instance. For more information, see Associate an EIP with an ECS instance.
NoteIf 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.
After you select Assign Public IPv4 Address, configure the Bandwidth Billing Method parameter to specify a billing method for network usage. In this example, the Bandwidth Billing Method parameter is set to Pay-by-traffic. 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.
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: select SSH (TCP:22), RDP (TCP:3389), HTTP (TCP:80), and HTTPS (TCP:443).
NoteIn the Open IPv4 Ports/Protocols section, select the ports that must be open 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 ECS 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.
Create a key pair
You can bind key pairs to ECS instances and use the key pairs as security credentials to authenticate your identity when you log on to the instances. After you create a key pair, download the private key of the key pair for subsequent use when you connect to the ECS instance. For more information, see 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.
root
is the highest-privileged account in the operating system. If you selectroot
as the logon username, security risks may arise. We recommend that you selectecs-user
as the logon username.NoteAfter you create the key pair, the private key of the key pair is automatically downloaded. View the download history of your browser and save the private key file, which is in the
.pem
format.
Create and view an ECS instance
After you create or select the required basic resources, read and select ECS Terms of Service and Product Terms of Service. Then, click Create Order. In the Success message, click Console to view the created ECS instance on the Instance page. Record the following information for later use:
Instance ID: You can search for the ECS instance by instance ID.
Region: You can search for the ECS instance by region.
Public IP address: You can use the public IP address of the ECS instance to check whether a web service is deployed on the instance.
Operation 2: Connect to the ECS instance
On the Instance page in the ECS console, find the ECS instance that you created based on its region and ID. Then, click Connect in the Actions column.
In the Remote connection dialog box, click Sign in now in the Workbench section.
In the Instance Login dialog box, set the Authentication parameter to SSH Key Authentication, set the Username parameter to
ecs-user
, enter or upload the private key file that you downloaded when you created the key pair, and then click OK.NoteThe private key file is automatically downloaded to your on-premises computer when you create the key pair. View the download history of your browser to find the private key file in the
.pem
format.If a page similar to that shown in the following figure appears, you are logged on to the ECS instance.
1. Configure user permissions
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 the RAM console
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 server.
Log on to the RAM console by using an Alibaba Cloud account or as an account administrator.
In the left-side navigation pane, choose Identities > Users.
On the Users page, click Create User.
Configure the Logon Name and Display Name parameters.
In the Access Mode section, select Using permanent AccessKey to access and click OK.
You can obtain the AccessKey secret of a RAM user only when you create the RAM user. You must keep the AccessKey secret secure to prevent credential leaks.
Click Copy in the Actions column of the page that appears to copy and paste the AccessKey pair to a securely stored file.
Operation 2: Grant the RAM user the permissions to call the AssumeRole operation in the RAM console
Grant the RAM user the permissions to call the AssumeRole operation. This way, the RAM user can obtain temporary access credentials by assuming a RAM role.
In the left-side navigation pane, choose Identities > Users.
On the Users page, find the RAM user to whom you want to grant permissions and click Add Permissions in the Actions column.
In the Policy section of the Grant Permission panel, select the AliyunSTSAssumeRoleAccess system policy.
NoteThe AliyunSTSAssumeRoleAccess policy allows a RAM user to call the AssumeRole operation. The permissions of the policy are independent of the permissions required for the RAM user to obtain temporary access credentials from STS and initiate requests to OSS.
Click Grant permissions.
Operation 3: Create a RAM role in the RAM console
Create a RAM role for the Alibaba Cloud account and obtain the Alibaba Cloud Resource Name (ARN) of the RAM role. The RAM role is assumed by the RAM user later.
In the left-side navigation pane, choose Identities > Roles.
On the Roles page, click Create Role. In the Select Role Type step of the Create Role wizard, set the Select Trusted Entity parameter to Alibaba Cloud Account and click Next.
In the Configure Role step of the Create Role wizard, enter a name in the RAM Role Name field and set the Select Trusted Alibaba Cloud Account parameter to Current Alibaba Cloud Account.
Click OK. After you create the role, click Close.
On the Roles page, enter the role name in the search box. Example:
oss-web-upload
. Click the name of the role.In the Basic Information section, click Copy next to the ARN field to record the ARN of the RAM role.
Operation 4: Create a custom policy in the RAM console
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.
In the left-side navigation pane, choose Permissions > Policies.
On the Policies page, click Create Policy.
On the Create Policy page, click JSON. Copy the following sample script and paste it into the code editor. Replace
<BucketName>
with the name of the bucket that you created, which isweb-direct-upload
.{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "oss:PutObject", "Resource": "acs:oss:*:*:<BucketName>/*" } ] }
After you configure the policy, click Next to edit policy information.
In the Basic Information section, specify the policy name and click OK.
Operation 5: Attach the custom policy to the RAM role in the RAM console
Attach the custom policy to the RAM role. This way, the RAM role has the required permissions when the RAM role is assumed.
In the left-side navigation pane, choose Identities > Roles.
On the Roles page, find the RAM role and click Grant Permission in the Actions column.
In the Policy section of the Grant Permission panel, select Custom Policy from the drop-down list, and then select the custom policy.
Click Grant permissions.
2. Obtain the temporary access credentials and calculate the signature on the application server
To prevent risks caused by explicitly specifying sensitive information, such as accessKeyId
, accessKeySecret
, and roleArn
, in the code, we recommend that you configure the sensitive information in environment variables.
You can add the environment variables as temporary environment variables and use them only in the current session.
Linux
Run the following command:
export OSS_ACCESS_KEY_ID="your-access-key-id" export OSS_ACCESS_KEY_SECRET="your-access-key-secret" export OSS_STS_ROLE_ARN="your-role-arn"
Run the following command to check whether the environment variables take effect:
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
macOS
Run the following command:
export OSS_ACCESS_KEY_ID="your-access-key-id" export OSS_ACCESS_KEY_SECRET="your-access-key-secret" export OSS_STS_ROLE_ARN="your-role-arn"
Run the following command to check whether the environment variables take effect:
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
Windows
Run the following command in cmd:
set OSS_ACCESS_KEY_ID "your-access-key-id" set OSS_ACCESS_KEY_SECRET "your-access-key-secret" set OSS_STS_ROLE_ARN "your-role-arn"
Open a new window.
Run the following command to check whether the environment variable takes effect in the new window:
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET echo $OSS_STS_ROLE_ARN
The following sample code provides an example on how to calculate V4 signatures in PostObject requests on the server. For more information, see (Recommended) Include a V4 signature in a PostObject request. For information about the configurations of the policy form field in a PostObject request, see policy.
Java
Add the following dependencies to the Maven project:
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>credentials-java</artifactId>
<version>0.3.4</version>
</dependency>
<dependency>
<groupId>com.aliyun.kms</groupId>
<artifactId>kms-transfer-client</artifactId>
<version>0.1.0</version>
</dependency>
<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, 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 {
// Specify the basic information. Replace the values with the actual bucket name, region ID, and host endpoint.
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.
// Specify the prefix contained in the names of the objects that you want to upload to OSS.
String upload_dir = "dir";
// Specify the validity period of the temporary access 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) {
// Obtain the current timestamp. Unit: seconds.
long now = Instant.now().getEpochSecond();
// Calculate the timestamp of the expiration time.
long expirationTime = now + seconds;
// Convert the timestamp into an instant object and format it in the ISO 8601 standard.
Instant instant = Instant.ofEpochSecond(expirationTime);
// Define the time zone.
ZoneId zone = ZoneId.systemDefault(); // Specify that the default time zone of the system is used.
// Convert the instance object into a ZonedDateTime object.
ZonedDateTime zonedDateTime = instant.atZone(zone);
// Specify the time format. Example: 2023-12-03T13:00:00.000Z.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
// Format the time.
String formattedDate = zonedDateTime.format(formatter);
// Output the result.
return formattedDate;
}
// Initialize an STSClient instance.
public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
// If the project code is leaked, the AccessKey pair may be leaked and the security of all resources within your account may be compromised. The following sample code is provided only for reference.
// We recommend that you use access credentials obtained from STS, which provide higher security.
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 of the region in which the bucket is located. 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()
// Required. 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 security token that are required for subsequent operations are included in the access 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 for reference only.
// Display the error message.
System.out.println(error.getMessage());
// Display the troubleshooting information.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Handle exceptions with caution in actual business scenarios and do not ignore the exceptions in your project. In this example, exceptions are provided for reference only.
// Display the error message.
System.out.println(error.getMessage());
// Display the troubleshooting information.
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
return null;
}
@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.
LocalDate today = LocalDate.now();
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 response mapping.
response.put("version", "OSS4-HMAC-SHA256");
// This configuration is prone to errors. You must perform Base64 encoding before you upload the policy.
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):
"""
Specify the function used to calculate the 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 configurations and pass the credentials.
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 of the request 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'
# Specify the date of the request.
dt_obj_2 = dt_obj.strftime('%Y%m%d')
# Specify the expiration time of the request.
expiration_time = dt_obj_plus_3h.strftime('%Y-%m-%dT%H:%M:%S.000Z')
# Specify the function that is used to encode the callback parameters 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()
# Return the 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="0.0.0.0", port=8000)
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",
"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, the content can be the image height and width. |
callbackBodyType | The content type of the request. Valid values:
|
The callback method that is used in the preceding example is provided only for reference. You can configure a callback method by modifying the server code. For more information, see Callback.
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"
)
// Specify 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 name of the bucket.
bucketName = "examplebucket"
// Specify the bucket to which you want to upload the object.
host := fmt.Sprintf("https://%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 server to which the 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 a form that is used to return the data to the front end.
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, // Return the directory to which the object 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)
}
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 an STSClient 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 temporary access credentials from STS.
const result=await sts.assumeRole(process.env.OSS_STS_ROLE_ARN, ', '3600', 'yourRoleSessionName'); // Obtain the ARN of the RAM role from the environment variables, 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 an OSSClient instance.
const client = new OSS({
bucket: 'examplebucket', // Replace examplebucket with the actual bucket name.
region: '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 form data map.
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 to 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 an upload callback request is sent. 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. 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 data in a form.
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 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}`);
});
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 the display of errors.
ini_set('display_errors', '0');
$bucket = 'examplebucket'; // Replace examplebucket with your bucket name.
$region_id = 'cn-hangzhou'; // Replace cn-hangzhou with the region in which the bucket is located.
$host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'; // Replace http://examplebucket.oss-cn-hangzhou.aliyuncs.com with the domain name of your bucket.
$expire_time = 3600; // Specify the validity period in seconds.
$upload_dir = 'user-dir'; // Specify the prefix in the name of the object that you want to upload to OSS.
// Set $callbackUrl to the URL of the callback server. Replace the IP address and port number with your actual information.
$callbackUrl = 'http://oss-demo.aliyuncs.com:23450/callback';
// Calculate the HMAC-SHA256 value.
function hmacsha256($key, $data) {
return hash_hmac('sha256', $data, $key, true);
}
// Processes the requests initiated to obtain the signature.
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;
?>
Step 3: Configure the web client
Create and submit a form upload request on the web client
After the web client receives the required information from the 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.
Sample 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 | The prefix contained in the names of the objects that you want to 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 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 when the request was initiated. The time must follow the ISO 8601 standard. Example: |
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.
Except for the file form field, the size of each form field (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 in OSS, 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 an object 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 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 last form field must be "file".
return fetch(data.host, {
method: "POST",
body: formData
});
})
.then((response) => {
if (response.ok) {
console.log("Uploaded");
alert("Object uploaded");
return response.json(); // Parse the callback information.
} else {
console.log("Upload failed", 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 box and a Submit icon. 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 you obtain the signature information, construct a
FormData
object that contains all the required form fields.You can use the
fetch
method to send a POST request to the URL of the OSS service and upload objects.
If the files are uploaded, the "File uploaded" message is displayed. If the files fail to be uploaded, an error message is displayed. The corresponding callback information is returned on the frontend page.
Verify the result
After you complete the preceding steps, you can access the application server to generate a signature and upload an object from a web client to OSS.
Enter the URL of the application server in a browser, select the object that you want to upload, and then click the Upload icon to upload the object.
On the Buckets page, click the name of the bucket that you created to store uploaded objects. On the page that appears, view the object that you uploaded from the web client.
Release resources
To build the web application, you created an ECS instance, an OSS bucket, a RAM user, and a RAM role. After you successfully upload objects to OSS, you can release the preceding resources to prevent unnecessary charges and eliminate relevant security risks.
Release the ECS instance
If you no longer require the ECS instance that you created, you can release the instance. After the ECS instance is released, billing for the instance stops, and the data on the instance is lost and cannot be restored. Procedure:
Go to the Instance page in the ECS console, find the ECS instance based on its region and instance ID, and then click the
icon in the Actions column.
Choose Instance Status > Release.
In the Release dialog box, set Release Mode to Release Now and click Next.
Confirm the associated resources that you want to release, read the notes about the data risks, select "I am aware of the instances and their associated resources to be released and understand the data risks", and then click OK.
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
Log on to the OSS console.
In the left-side navigation pane, click Buckets. On the Buckets page, click the name of the bucket that you want to delete.
Delete all objects in the bucket and then delete the bucket.
In the left-side navigation tree, click Delete Bucket. On the Delete Bucket page, follow the on-screen instructions to delete the bucket.
Delete the RAM user
Log on to the RAM console as a RAM user who has admin privileges.
In the left-side navigation pane, choose Identities > Users.
On the Users page, find the RAM user that you want to delete and click Delete in the Actions column.
You can also select multiple RAM users and click Delete User below the RAM user list to move all selected RAM users to the recycle bin at the same time.
In the Delete User dialog box, read the statement on the impact of the delete operation, enter the name of the RAM user, and then click Move to Recycle Bin.
Delete the RAM role
Log on to the RAM console as a RAM user who has admin privileges.
In the left-side navigation pane, choose Identities > Roles.
On the Roles page, find the RAM role that you want to delete and click Delete Role in the Actions column.
In the Delete Role dialog box, enter the name of the RAM role and click Delete Role.
NoteIf 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?
OSS does not provide API operations for you to upload multiple objects 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 can only 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.