This topic explains how to use Security Token Service (STS) and signed URLs to grant temporary access to OSS resources.
Authorization methods
OSS offers several authorization methods for clients. This topic covers three of these methods, including code examples for simple uploads, to help you select the best fit for your use case.
Method | Process | Best for | Considerations |
| Ideal for most uploads. In this approach, your application server obtains temporary access credentials from STS, which the client then uses with an OSS SDK. This method supports multipart and resumable uploads because the client can reuse the credentials to sign each part. | Frequent calls to STS may lead to request throttling. To avoid this, cache the temporary access credentials and refresh them before expiration. To prevent misuse, apply granular policy restrictions to the credentials. | |
Method 2: Server-generated signature and Post Policy for PostObject |
| Best for HTML form uploads that require constraints on file attributes like size or type. The application server provides a signature and a Post Policy, allowing the client to upload files directly without an OSS SDK. This method does not support multipart or resumable uploads. | Does not support multipart or resumable uploads. |
| Ideal for simple uploads where the client can upload a file directly using the URL, without needing an OSS SDK. | Unsuitable for multipart or resumable uploads. Generating a signed URL for each part increases server load and network overhead. It also complicates ensuring upload integrity, as a client could modify or reorder parts, risking data corruption. |
Generate server-side STS temporary access credentials
A validity period must be specified for STS temporary access credentials and a signed URL. When you use temporary access credentials to generate a signed URL that is used to perform operations, such as object uploads and downloads, the minimum validity period takes precedence. For example, you can set the validity period of your temporary access credentials to 1,200 seconds and the validity period of the signed URL generated by using the credentials to 3,600 seconds. In this case, the signed URL cannot be used to upload objects after the STS temporary access credentials expire, even if the signed URL is within its validity period.
The following diagram illustrates how the application server generates an STS temporary access credential to authorize a client to upload files to OSS.
Sample code
The following examples show the core code snippets. For the complete code, see the sample project: sts.zip.
Server-side sample code
The following examples show how to generate a temporary access credential on the server.
Java
import com.aliyun.sts20150401.Client;
import com.aliyun.sts20150401.models.AssumeRoleRequest;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.models.RuntimeOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.aliyun.teaopenapi.models.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.aliyun.teautil.Common.assertAsString;
@RestController
public class StsController {
@Autowired
private Client stsClient;
@GetMapping("/get_sts_token_for_oss_upload")
public AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials generateStsToken() {
AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest()
.setDurationSeconds(3600L)
// Set <YOUR_ROLE_SESSION_NAME> to a custom session name, for example, my-website-server.
.setRoleSessionName("<YOUR_ROLE_SESSION_NAME>")
// Replace <YOUR_ROLE_ARN> with the ARN of the RAM role that has permissions to upload files to the specified OSS bucket. You can find the role ARN on the RAM Role Details page.
.setRoleArn("<YOUR_ROLE_ARN>");
RuntimeOptions runtime = new RuntimeOptions();
try {
AssumeRoleResponse response = stsClient.assumeRoleWithOptions(assumeRoleRequest, runtime);
return response.body.credentials;
} catch (TeaException error) {
// Print the error if necessary.
assertAsString(error.message);
return null;
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// Print the error if necessary.
assertAsString(error.message);
return null;
}
}
}
@Configuration
public class StsClientConfiguration {
@Bean
public Client stsClient() {
// If you initialize the credential client without parameters, it uses the default credential chain.
Config config = new Config();
config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
try {
com.aliyun.credentials.Client credentials = new com.aliyun.credentials.Client();
config.setCredential(credentials);
return new Client(config);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}Node.js
const express = require("express");
const { STS } = require('ali-oss');
const app = express();
const path = require("path");
app.use(express.static(path.join(__dirname, "templates")));
// Configure the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
const accessKeyId = process.env.ALIBABA_CLOUD_ACCESS_KEY_ID;
// Configure the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
const accessKeySecret = process.env.ALIBABA_CLOUD_ACCESS_SECRET;
app.get('/get_sts_token_for_oss_upload', (req, res) => {
let sts = new STS({
accessKeyId: accessKeyId,
accessKeySecret: accessKeySecret
});
// For the first parameter, roleArn, specify the ARN of your RAM role. Example: acs:ram::175708322470****:role/ramtest.
// For the second parameter, policy, you can specify a custom policy to further restrict the permissions of the temporary access credential. If you do not specify a policy, the credential inherits all permissions from the role by default.
// The third parameter, 3000, specifies the expiration time in seconds.
// The fourth parameter, 'sessiontest', is a custom session name used to distinguish different tokens.
sts.assumeRole('<YOUR_ROLE_ARN>', ``, '3000', 'sessiontest').then((result) => {
console.log(result);
res.json({
AccessKeyId: result.credentials.AccessKeyId,
AccessKeySecret: result.credentials.AccessKeySecret,
SecurityToken: result.credentials.SecurityToken,
});
}).catch((err) => {
console.log(err);
res.status(400).json(err.message);
});
});
app.listen(8000, () => {
console.log("http://127.0.0.1:8000");
});
Python
import json
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
from alibabacloud_credentials.client import Client as CredentialClient
# Replace <YOUR_ROLE_ARN> with the ARN of the RAM role with permissions to upload files to the specified OSS bucket.
role_arn_for_oss_upload = '<YOUR_ROLE_ARN>'
# Set <YOUR_REGION_ID> to the region of the STS service, for example, cn-hangzhou.
region_id = '<YOUR_REGION_ID>'
def get_sts_token():
# If you do not specify parameters when you initialize CredentialClient, the client uses the default credential chain.
# When you run the program locally, you can specify the AccessKey pair using the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.
# When you run the program on an ECS instance, in ECI, or in Container Service, you can specify the bound instance RAM role using the ALIBABA_CLOUD_ECS_METADATA environment variable. The SDK automatically obtains an STS temporary access credential.
config = Config(region_id=region_id, credential=CredentialClient())
sts_client = Sts20150401Client(config=config)
assume_role_request = sts_20150401_models.AssumeRoleRequest(
role_arn=role_arn_for_oss_upload,
# Set <YOUR_ROLE_SESSION_NAME> to a custom session name, for example, oss-role-session.
role_session_name='<YOUR_ROLE_SESSION_NAME>'
)
response = sts_client.assume_role(assume_role_request)
token = json.dumps(response.body.credentials.to_map())
return token
Go
package main
import (
"encoding/json"
"net/http"
"os"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
sts20150401 "github.com/alibabacloud-go/sts-20150401/v2/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
/**
* Initialize a client using an access key pair (AccessKey ID and AccessKey Secret).
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
func CreateClient(accessKeyId *string, accessKeySecret *string) (*sts20150401.Client, error) {
config := &openapi.Config{
// Required. Your AccessKey ID.
AccessKeyId: accessKeyId,
// Required. Your AccessKey Secret.
AccessKeySecret: accessKeySecret,
}
// For the endpoint, see https://api.aliyun.com/product/Sts.
config.Endpoint = tea.String("sts.cn-hangzhou.aliyuncs.com")
return sts20150401.NewClient(config)
}
func AssumeRole(client *sts20150401.Client) (*sts20150401.AssumeRoleResponse, error) {
assumeRoleRequest := &sts20150401.AssumeRoleRequest{
DurationSeconds: tea.Int64(3600),
RoleArn: tea.String("acs:ram::1379186349531844:role/admin-oss"),
RoleSessionName: tea.String("peiyu-demo"),
}
return client.AssumeRoleWithOptions(assumeRoleRequest, &util.RuntimeOptions{})
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "templates/index.html")
return
} else if r.URL.Path == "/get_sts_token_for_oss_upload" {
client, err := CreateClient(tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")), tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")))
if err != nil {
panic(err)
}
assumeRoleResponse, err := AssumeRole(client)
if err != nil {
panic(err)
}
responseBytes, err := json.Marshal(assumeRoleResponse)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
w.Write(responseBytes)
return
}
http.NotFound(w, r)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
PHP
<?php
require_once 'vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;
// Initialize the Alibaba Cloud client.
AlibabaCloud::accessKeyClient(getenv('ALIBABA_CLOUD_ACCESS_KEY_ID'), getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'))
->regionId('cn-hangzhou')
->asDefaultClient();
// Create an STS request.
$request = Sts::v20150401()->assumeRole();
// Send the STS request and get the result.
// Set <YOUR_ROLE_SESSION_NAME> to a custom session name, for example, oss-role-session.
// Replace <YOUR_ROLE_ARN> with the ARN of the RAM role with permissions to upload files to the specified OSS bucket.
$result = $request
->withRoleSessionName("<YOUR_ROLE_SESSION_NAME>")
->withDurationSeconds(3600)
->withRoleArn("<YOUR_ROLE_ARN>")
->request();
// Get the credential information from the STS response.
$credentials = $result->get('Credentials');
// Build the returned JSON data.
$response = [
'AccessKeyId' => $credentials['AccessKeyId'],
'AccessKeySecret' => $credentials['AccessKeySecret'],
'SecurityToken' => $credentials['SecurityToken'],
];
// Set the response header to application/json.
header('Content-Type: application/json');
// Convert the result to JSON format and print it.
echo json_encode(['Credentials' => $response]);
?>
C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Aliyun.OSS;
using System;
using System.IO;
using AlibabaCloud.SDK.Sts20150401;
using System.Text.Json;
namespace YourNamespace
{
public class Program
{
private ILogger<Program> _logger;
public static AlibabaCloud.SDK.Sts20150401.Client CreateClient(string accessKeyId, string accessKeySecret)
{
var config = new AlibabaCloud.OpenApiClient.Models.Config
{
AccessKeyId = accessKeyId,
AccessKeySecret = accessKeySecret,
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
};
return new AlibabaCloud.SDK.Sts20150401.Client(config);
}
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
builder.Logging.AddConsole();
var serviceProvider = builder.Services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
app.UseStaticFiles();
app.MapGet("/", async (context) =>
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
var htmlContent = await File.ReadAllTextAsync(filePath);
await context.Response.WriteAsync(htmlContent);
logger.LogInformation("GET request to root path");
});
app.MapGet("/get_sts_token_for_oss_upload", async (context) =>
{
var program = new Program(logger);
var client = CreateClient(Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID"), Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
// Set <YOUR_ROLE_SESSION_NAME> to a custom session name, for example, oss-role-session.
assumeRoleRequest.RoleSessionName = "<YOUR_ROLE_SESSION_NAME>";
// Replace <YOUR_ROLE_ARN> with the ARN of the RAM role with permissions to upload files to the specified OSS bucket.
assumeRoleRequest.RoleArn = "<YOUR_ROLE_ARN>";
assumeRoleRequest.DurationSeconds = 3600;
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
var credentials = response.Body.Credentials;
var jsonResponse = JsonSerializer.Serialize(new
{
AccessKeyId = credentials.AccessKeyId,
AccessKeySecret = credentials.AccessKeySecret,
Expiration = credentials.Expiration,
SecurityToken = credentials.SecurityToken
});
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(jsonResponse);
});
app.Run();
}
public Program(ILogger<Program> logger)
{
_logger = logger;
}
}
}Ruby
require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
require 'aliyunsdkcore'
# Set the path of the public folder to the templates folder in the current directory.
set :public_folder, File.dirname(__FILE__) + '/templates'
def get_sts_token_for_oss_upload()
client = RPCClient.new(
# Configure the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
access_key_id: ENV['ALIBABA_CLOUD_ACCESS_KEY_ID'],
# Configure the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
access_key_secret: ENV['ALIBABA_CLOUD_ACCESS_KEY_SECRET'],
endpoint: 'https://sts.cn-hangzhou.aliyuncs.com',
api_version: '2015-04-01'
)
response = client.request(
action: 'AssumeRole',
params: {
# For RoleArn, specify the ARN of your RAM role. Example: acs:ram::175708322470****:role/ramtest.
"RoleArn": "acs:ram::175708322470****:role/ramtest",
# 3600 specifies the expiration time in seconds.
"DurationSeconds": 3600,
# For RoleSessionName, specify a custom session name to distinguish different tokens. Example: sessiontest.
"RoleSessionName": "sessiontest"
},
opts: {
method: 'POST',
format_params: true
}
)
end
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
$server_ip = "0.0.0.0"
$server_port = 8000
puts "App server is running on: http://#{$server_ip}:#{$server_port}"
set :bind, $server_ip
set :port, $server_port
get '/get_sts_token_for_oss_upload' do
token = get_sts_token_for_oss_upload()
response = {
"AccessKeyId" => token["Credentials"]["AccessKeyId"],
"AccessKeySecret" => token["Credentials"]["AccessKeySecret"],
"SecurityToken" => token["Credentials"]["SecurityToken"]
}
response.to_json
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
endClient-side sample code
The following example shows how a web client can use a temporary access credential to upload a file to OSS.
let credentials = null;
const form = document.querySelector("form");
form.addEventListener("submit", async (event) => {
event.preventDefault();
// To reduce calls to the STS service, fetch new credentials only when the current ones are about to expire.
if (isCredentialsExpired(credentials)) {
const response = await fetch("/get_sts_token_for_oss_upload", {
method: "GET",
});
if (!response.ok) {
// Handle non-2xx HTTP status codes.
throw new Error(
`Failed to get STS token: ${response.status} ${response.statusText}`
);
}
credentials = await response.json();
}
const client = new OSS({
// Set <YOUR_BUCKET> to your OSS bucket name.
bucket: "<YOUR_BUCKET>",
// Set <YOUR_REGION> to the region where your OSS bucket is located. For example, use 'oss-cn-hangzhou'.
region: "oss-<YOUR_REGION>",
authorizationV4: true,
accessKeyId: credentials.AccessKeyId,
accessKeySecret: credentials.AccessKeySecret,
stsToken: credentials.SecurityToken,
});
const fileInput = document.querySelector("#file");
const file = fileInput.files[0];
const result = await client.put(file.name, file);
console.log(result);
});
/**
* Checks if the temporary credentials have expired.
**/
function isCredentialsExpired(credentials) {
if (!credentials) {
return true;
}
const expireDate = new Date(credentials.Expiration);
const now = new Date();
// The credentials are considered expired if the remaining validity period is one minute or less.
return expireDate.getTime() - now.getTime() <= 60000;
}Server-side signature and post policy
This diagram shows how a server-side application provides a signature and a post policy to authorize a client-side application to upload files to OSS.
Code examples
These examples show the core code. For the complete code, see the sample project: postsignature.zip.
Server-side code examples
The server-side code generates a signature, a post policy, and other required information.
Java
import com.aliyun.help.demo.uploading_to_oss_directly_postsignature.config.OssConfig;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.codehaus.jettison.json.JSONObject;
import java.util.Date;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import javax.annotation.PreDestroy;
@Controller
public class PostSignatureController {
@Autowired
private OSS ossClient;
@Autowired
private OssConfig ossConfig;
@GetMapping("/get_post_signature_for_oss_upload")
@ResponseBody
public String generatePostSignature() {
JSONObject response = new JSONObject();
try {
long expireEndTime = System.currentTimeMillis() + ossConfig.getExpireTime() * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, ossConfig.getDir());
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
response.put("ossAccessKeyId", ossConfig.getAccessKeyId());
response.put("policy", encodedPolicy);
response.put("signature", postSignature);
response.put("dir", ossConfig.getDir());
response.put("host", ossConfig.getHost());
} catch (
OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
// Assume this method exists.
System.out.println("HTTP Status Code: " + oe.getRawResponseError());
System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message: " + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
return response.toString();
}
}
}
@Configuration
public class OssConfig {
/**
* Replace <YOUR-ENDPOINT> with your endpoint. Example: oss-cn-hangzhou.aliyuncs.com.
*/
private String endpoint = "<YOUR-ENDPOINT>";
/**
* Replace <YOUR-BUCKET> with your bucket name.
*/
private String bucket = "<YOUR-BUCKET>";
/**
* Specify the object prefix for uploads to OSS.
*/
private String dir = "user-dir-prefix/";
/**
* Specify the expiration time in seconds.
*/
private long expireTime = 3600;
/**
* Construct the host.
*/
private String host = "http://" + bucket + "." + endpoint;
/**
* Set accessKeyId using the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
*/
private String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
/**
* Set accessKeySecret using the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
*/
private String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
private OSS ossClient;
@Bean
public OSS getOssClient() {
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
return ossClient;
}
@Bean
public String getHost() {
return host;
}
@Bean
public String getAccessKeyId() {
return accessKeyId;
}
@Bean
public long getExpireTime() {
return expireTime;
}
@Bean
public String getDir() {
return dir;
}
@PreDestroy
public void onDestroy() {
ossClient.shutdown();
}
}
Node.js
const express = require("express");
const { Buffer } = require("buffer");
const OSS = require("ali-oss");
const app = express();
const path = require("path");
const config = {
// Set the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
// Set the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
// Replace <YOUR-BUCKET> with your bucket name.
bucket: "<YOUR-BUCKET>",
// Specify the object prefix for uploads to OSS.
dir: "prefix/",
};
app.use(express.static(path.join(__dirname, "templates")));
app.get("/get_post_signature_for_oss_upload", async (req, res) => {
const client = new OSS(config);
const date = new Date();
// Set the validity period of the signature in seconds.
date.setSeconds(date.getSeconds() + 3600);
const policy = {
expiration: date.toISOString(),
conditions: [
// Set the size limit for the uploaded object.
["content-length-range", 0, 1048576000],
// Restrict the bucket to which objects can be uploaded.
{ bucket: client.options.bucket },
],
};
const formData = await client.calculatePostSignature(policy);
const host = `http://${config.bucket}.${
(await client.getBucketLocation()).location
}.aliyuncs.com`.toString();
const params = {
policy: formData.policy,
signature: formData.Signature,
ossAccessKeyId: formData.OSSAccessKeyId,
host,
dir: config.dir,
};
res.json(params);
});
app.get(/^(.+)*\.(html|js)$/i, async (req, res) => {
res.sendFile(path.join(__dirname, "./templates", req.originalUrl));
});
app.listen(8000, () => {
console.log("http://127.0.0.1:8000");
});
Python
import os
from hashlib import sha1 as sha
import json
import base64
import hmac
import datetime
import time
# Set the OSS_ACCESS_KEY_ID environment variable.
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
# Set the OSS_ACCESS_KEY_SECRET environment variable.
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
# Replace <YOUR_BUCKET> with your bucket name.
bucket = '<YOUR_BUCKET>'
# The host format is bucketname.endpoint. Replace <YOUR_BUCKET> with your bucket name and <YOUR_ENDPOINT> with your OSS endpoint. Example: oss-cn-hangzhou.aliyuncs.com.
host = 'https://<YOUR_BUCKET>.<YOUR_ENDPOINT>'
# Specify the object prefix for uploads to OSS.
upload_dir = 'user-dir-prefix/'
# Specify the expiration time in seconds.
expire_time = 3600
def generate_expiration(seconds):
"""
Generates an expiration time by specifying a validity period in seconds.
:param seconds: The validity period in seconds.
:return: An ISO 8601 time string. Example: "2014-12-01T12:00:00.000Z".
"""
now = int(time.time())
expiration_time = now + seconds
gmt = datetime.datetime.utcfromtimestamp(expiration_time).isoformat()
gmt += 'Z'
return gmt
def generate_signature(access_key_secret, expiration, conditions, policy_extra_props=None):
"""
Generates the signature string.
:param access_key_secret: The AccessKeySecret that has permissions to access the destination bucket.
:param expiration: The signature expiration time in ISO 8601 UTC format. Example: "2014-12-01T12:00:00.000Z".
:param conditions: The policy conditions that restrict the allowed values in the upload form.
:param policy_extra_props: Additional policy parameters. If new parameters are supported later, you can pass them in using a dict.
:return: signature, the signature string.
"""
policy_dict = {
'expiration': expiration,
'conditions': conditions
}
if policy_extra_props is not None:
policy_dict.update(policy_extra_props)
policy = json.dumps(policy_dict).strip()
policy_encode = base64.b64encode(policy.encode())
h = hmac.new(access_key_secret.encode(), policy_encode, sha)
sign_result = base64.b64encode(h.digest()).strip()
return sign_result.decode()
def generate_upload_params():
policy = {
# Expiration time.
"expiration": generate_expiration(expire_time),
# Conditions.
"conditions": [
# The status code to return on successful upload if success_action_redirect is not specified. Default: 204.
["eq", "$success_action_status", "200"],
# The value of the key form field must start with a specified prefix. For example, to require that the key starts with 'user/user1', specify ["starts-with", "$key", "user/user1"].
["starts-with", "$key", upload_dir],
# Restricts the minimum and maximum allowed size of the uploaded object in bytes.
["content-length-range", 1, 1000000],
# Restricts uploads to the specified image types.
["in", "$content-type", ["image/jpeg", "image/png"]]
]
}
signature = generate_signature(access_key_secret, policy.get('expiration'), policy.get('conditions'))
response = {
'policy': base64.b64encode(json.dumps(policy).encode('utf-8')).decode(),
'ossAccessKeyId': access_key_id,
'signature': signature,
'host': host,
'dir': upload_dir
# You can add other custom parameters here.
}
return json.dumps(response)
Go
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
var (
// Set the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
accessKeyId = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
// Set the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
accessKeySecret = os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
// The host format is bucketname.endpoint. Replace ${your-bucket} with your bucket name and ${your-endpoint} with your OSS endpoint. Example: oss-cn-hangzhou.aliyuncs.com.
host = "http://${your-bucket}.${your-endpoint}"
// Specify the object prefix for uploads to OSS.
uploadDir = "user-dir-prefix/"
// Specify the expiration time in seconds.
expireTime = int64(3600)
)
type ConfigStruct struct {
Expiration string `json:"expiration"`
Conditions [][]string `json:"conditions"`
}
type PolicyToken struct {
AccessKeyId string `json:"ossAccessKeyId"`
Host string `json:"host"`
Signature string `json:"signature"`
Policy string `json:"policy"`
Directory string `json:"dir"`
}
func getGMTISO8601(expireEnd int64) string {
return time.Unix(expireEnd, 0).UTC().Format("2006-01-02T15:04:05Z")
}
func getPolicyToken() string {
now := time.Now().Unix()
expireEnd := now + expireTime
tokenExpire := getGMTISO8601(expireEnd)
var config ConfigStruct
config.Expiration = tokenExpire
var condition []string
condition = append(condition, "starts-with")
condition = append(condition, "$key")
condition = append(condition, uploadDir)
config.Conditions = append(config.Conditions, condition)
result, err := json.Marshal(config)
if err != nil {
fmt.Println("callback json err:", err)
return ""
}
encodedResult := base64.StdEncoding.EncodeToString(result)
h := hmac.New(sha1.New, []byte(accessKeySecret))
io.WriteString(h, encodedResult)
signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
policyToken := PolicyToken{
AccessKeyId: accessKeyId,
Host: host,
Signature: signedStr,
Policy: encodedResult,
Directory: uploadDir,
}
response, err := json.Marshal(policyToken)
if err != nil {
fmt.Println("json err:", err)
return ""
}
return string(response)
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "templates/index.html")
return
} else if r.URL.Path == "/get_post_signature_for_oss_upload" {
policyToken := getPolicyToken()
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(policyToken))
return
}
http.NotFound(w, r)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
PHP
<?php
function gmt_iso8601($time)
{
return str_replace('+00:00', '.000Z', gmdate('c', $time));
}
// Get access credentials from environment variables. Before you run this example, make sure the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables are set.
$accessKeyId = getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
$accessKeySecret = getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// The format of $host is '<YOUR-BUCKET>.<YOUR-ENDPOINT>'. Replace the placeholders with your actual information.
$host = 'http://<YOUR-BUCKET>.<YOUR-ENDPOINT>';
// The object prefix specified by the user for uploads.
$dir = 'user-dir-prefix/';
$now = time();
// Set the policy expiration time to 3600 seconds (1 hour).
$expire = 3600;
$end = $now + $expire;
$expiration = gmt_iso8601($end);
//Maximum file size. You can change this value.
$condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
$conditions[] = $condition;
// Uploaded object keys must start with $dir. Otherwise, the upload will fail. This is not required but is a security measure to prevent users from uploading to other directories.
$start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
$conditions[] = $start;
$arr = array('expiration' => $expiration, 'conditions' => $conditions);
$policy = json_encode($arr);
$base64_policy = base64_encode($policy);
$string_to_sign = $base64_policy;
$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $accessKeySecret, true));
$response = array();
$response['ossAccessKeyId'] = $accessKeyId;
$response['host'] = $host;
$response['policy'] = $base64_policy;
$response['signature'] = $signature;
$response['dir'] = $dir;
echo json_encode($response);
Ruby
require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
# Set the public folder path to the templates folder in the current directory.
set :public_folder, File.dirname(__FILE__) + '/templates'
# Set the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
$access_key_id = ENV['ALIBABA_CLOUD_ACCESS_ID']
# Set the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
$access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_SECRET']
# The format of $host is '<bucketname>.<endpoint>'. Replace the placeholders with your actual information.
$host = 'http://<bucketname>.<endpoint>';
# The object prefix specified by the user for uploads.
$upload_dir = 'user-dir-prefix/'
# Expiration time in seconds.
$expire_time = 3600
$server_ip = "0.0.0.0"
$server_port = 8000
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
puts "App server is running on: http://#{$server_ip}:#{$server_port}"
def hash_to_jason(source_hash)
jason_string = source_hash.to_json;
jason_string.gsub!("\":[", "\": [")
jason_string.gsub!("\",\"", "\", \"")
jason_string.gsub!("],\"", "], \"")
jason_string.gsub!("\":\"", "\": \"")
jason_string
end
def get_token()
expire_syncpoint = Time.now.to_i + $expire_time
expire = Time.at(expire_syncpoint).utc.iso8601()
response.headers['expire'] = expire
policy_dict = {}
condition_arrary = Array.new
array_item = Array.new
array_item.push('starts-with')
array_item.push('$key')
array_item.push($upload_dir)
condition_arrary.push(array_item)
policy_dict["conditions"] = condition_arrary
policy_dict["expiration"] = expire
policy = hash_to_jason(policy_dict)
policy_encode = Base64.strict_encode64(policy).chomp;
h = OpenSSL::HMAC.digest('sha1', $access_key_secret, policy_encode)
sign_result = Base64.strict_encode64(h).strip()
token_dict = {}
token_dict['ossAccessKeyId'] = $access_key_id
token_dict['host'] = $host
token_dict['policy'] = policy_encode
token_dict['signature'] = sign_result
token_dict['expire'] = expire_syncpoint
token_dict['dir'] = $upload_dir
result = hash_to_jason(token_dict)
result
end
set :bind, $server_ip
set :port, $server_port
get '/get_post_signature_for_oss_upload' do
token = get_token()
puts "Token: #{token}"
token
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
end
end
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
$server_ip = "0.0.0.0"
$server_port = 8000
puts "App server is running on: http://#{$server_ip}:#{$server_port}"
set :bind, $server_ip
set :port, $server_port
get '/get_sts_token_for_oss_upload' do
token = get_sts_token_for_oss_upload()
response = {
"AccessKeyId" => token["Credentials"]["AccessKeyId"],
"AccessKeySecret" => token["Credentials"]["AccessKeySecret"],
"SecurityToken" => token["Credentials"]["SecurityToken"]
}
response.to_json
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
end
C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.Collections.Generic;
using System;
using System.Globalization;
using System.Text;
using System.Security.Cryptography;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace YourNamespace
{
public class Program
{
private ILogger<Program> _logger;
// Set the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
// Set the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// The host format is bucketname.endpoint. Replace <YOUR-BUCKET> with your bucket name and <YOUR-ENDPOINT> with your OSS endpoint. Example: oss-cn-hangzhou.aliyuncs.com.
public string Host { get; set; } = "<YOUR-BUCKET>.<YOUR-ENDPOINT>";
// Specify the object prefix for uploads to OSS.
public string UploadDir { get; set; } = "user-dir-prefix/";
// Specify the expiration time in seconds.
public int ExpireTime { get; set; } = 3600;
public class PolicyConfig
{
public string expiration { get; set; }
public List<List<object>> conditions { get; set; }
}
public class PolicyToken
{
public string OssAccessKeyId { get; set; }
public string Policy { get; set; }
public string Signature { get; set; }
public string Dir { get; set; }
public string Host { get; set; }
public string Expire { get; set; }
}
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
builder.Logging.AddConsole();
var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
app.UseStaticFiles();
app.MapGet("/", async (context) =>
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
var htmlContent = await File.ReadAllTextAsync(filePath);
await context.Response.WriteAsync(htmlContent);
logger.LogInformation("GET request to root path");
});
app.MapGet("/get_post_signature_for_oss_upload", async (context) =>
{
var program = new Program(logger);
var token = program.GetPolicyToken();
logger.LogInformation($"Token: {token}");
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(token);
});
app.Run();
}
public Program(ILogger<Program> logger)
{
_logger = logger;
}
private static string ToUnixTime(DateTime dateTime)
{
return ((DateTimeOffset)dateTime).ToUnixTimeSeconds().ToString();
}
private string GetPolicyToken()
{
var expireDateTime = DateTime.Now.AddSeconds(ExpireTime);
var config = new PolicyConfig
{
expiration = FormatIso8601Date(expireDateTime),
conditions = new List<List<object>>()
};
config.conditions.Add(new List<object>
{
"content-length-range", 0, 1048576000
});
var policy = JsonConvert.SerializeObject(config);
var policyBase64 = EncodeBase64("utf-8", policy);
var signature = ComputeSignature(AccessKeySecret, policyBase64);
var policyToken = new PolicyToken
{
OssAccessKeyId = AccessKeyId,
Host = Host,
Policy = policyBase64,
Signature = signature,
Expire = ToUnixTime(expireDateTime),
Dir = UploadDir
};
return JsonConvert.SerializeObject(policyToken);
}
private static string FormatIso8601Date(DateTime dtime)
{
return dtime.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'",
CultureInfo.CurrentCulture);
}
private static string EncodeBase64(string codeType, string code)
{
string encode = "";
byte[] bytes = Encoding.GetEncoding(codeType).GetBytes(code);
try
{
encode = Convert.ToBase64String(bytes);
}
catch
{
encode = code;
}
return encode;
}
private static string ComputeSignature(string key, string data)
{
using (var algorithm = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
{
return Convert.ToBase64String(algorithm.ComputeHash(Encoding.UTF8.GetBytes(data)));
}
}
}
}
Client-side code example
This example shows how a web client uses the signature, post policy, and other information from the server to upload a file to OSS.
const form = document.querySelector("form");
const fileInput = document.querySelector("#file");
form.addEventListener("submit", (event) => {
event.preventDefault();
const file = fileInput.files[0];
const filename = fileInput.files[0].name;
fetch("/get_post_signature_for_oss_upload", { method: "GET" })
.then((response) => {
if (!response.ok) {
throw new Error("Failed to get signature");
}
return response.json();
})
.then((data) => {
const formData = new FormData();
formData.append("name", filename);
formData.append("policy", data.policy);
formData.append("OSSAccessKeyId", data.ossAccessKeyId);
formData.append("success_action_status", "200");
formData.append("signature", data.signature);
formData.append("key", data.dir + filename);
formData.append("file", file);
return fetch(data.host, { method: "POST", body: formData });
})
.then((response) => {
if (response.ok) {
console.log("Upload successful");
alert("File uploaded");
} else {
console.log("Upload failed", response);
alert("Upload failed. Please try again later.");
}
})
.catch((error) => {
console.error("An error occurred:", error);
});
});Server-side presigned URL for PutObject
When using a presigned URL with optional parameters, ensure the Content-Type specified during URL generation on the server side matches the Content-Type set by the client. Otherwise, a SignatureDoesNotMatch error may occur. For details on setting the Content-Type, see How do I set the Content-Type (MIME)?.
The following diagram illustrates how to authorize a client to upload a file to OSS using a presigned URL generated on the server side.
Sample code
The following examples show the core code. For the complete code, see the sample project: presignedurl.zip.
Server-side sample code
The following example shows how to generate a presigned URL on the server side:
Java
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.net.URL;
import java.util.Date;
import javax.annotation.PreDestroy;
@Configuration
public class OssConfig {
/**
* Configure the OSS endpoint, for example, oss-cn-hangzhou.aliyuncs.com.
*/
private static final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
/**
* Set accessKeyId from the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
*/
@Value("${ALIBABA_CLOUD_ACCESS_KEY_ID}")
private String accessKeyId;
/**
* Set accessKeySecret from the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
*/
@Value("${ALIBABA_CLOUD_ACCESS_KEY_SECRET}")
private String accessKeySecret;
private OSS ossClient;
@Bean
public OSS getSssClient() {
// Specify the region where the bucket is located. For China (Hangzhou), set the region to cn-hangzhou.
String region = "cn-hangzhou";
// Create an OSSClient instance.
// Call the shutdown method to release resources when the OSSClient instance is no longer needed.
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
return ossClient;
}
@PreDestroy
public void onDestroy() {
ossClient.shutdown();
}
}
@Controller
public class PresignedURLController {
/**
* Replace <your-bucket> with the bucket name.
* Replace <your-object> with the full object key, for example, exampleobject.txt. The object key cannot contain the bucket name.
* Specify the expiration time in milliseconds.
*/
private static final String BUCKET_NAME = "<your-bucket>";
private static final String OBJECT_NAME = "<your-object>";
private static final long EXPIRE_TIME = 3600 * 1000L;
@Autowired
private OSS ossClient;
@GetMapping("/get_presigned_url_for_oss_upload")
@ResponseBody
public String generatePresignedURL() {
try {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(BUCKET_NAME, OBJECT_NAME, HttpMethod.PUT);
Date expiration = new Date(System.currentTimeMillis() + EXPIRE_TIME);
request.setExpiration(expiration);
request.setContentType("image/png");
URL signedUrl = ossClient.generatePresignedUrl(request);
return signedUrl.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}Node.js
const express = require("express");
const OSS = require("ali-oss");
const app = express();
app.get("/get_presigned_url_for_oss_upload", async (req, res) => {
const client = new OSS({
// Obtain the values of AccessKey ID, AccessKey Secret, and STS token from environment variables.
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
stsToken: process.env.ALIBABA_CLOUD_SECURITY_TOKEN,
// Replace 'yourBucket' with your bucket name.
bucket: 'yourBucket',
// Replace 'yourRegion' with the region where your bucket is located.
region: 'yourRegion',
authorizationV4: true,
});
return await client.signatureUrlV4('PUT', 3600, {
// Set the request headers based on the actual headers to be sent.
headers: {},
}, 'demo.pdf');
});
app.listen(8000, () => {
console.log("http://127.0.0.1:8000");
});
Python
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# Obtain access credentials from environment variables. Before you run this sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured.
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# Specify the endpoint of the region where the bucket is located. For the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com.
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# Specify the region that corresponds to the endpoint, for example, cn-hangzhou. Note that this parameter is required for V4 signatures.
region = "cn-hangzhou"
# Replace 'examplebucket' with your bucket name.
bucket = oss2.Bucket(auth, endpoint, "examplebucket", region=region)
# Specify an expiration time of 3,600 seconds. The maximum expiration time is 32,400 seconds.
expire_time = 3600
# Specify the full object key, for example, exampledir/exampleobject.png. The object key cannot contain the bucket name.
object_name = 'exampledir/exampleobject.png'
def generate_presigned_url():
# Specify the headers.
headers = dict()
# Specify the Content-Type.
headers['Content-Type'] = 'image/png'
# Specify the storage class.
# headers["x-oss-storage-class"] = "Standard"
# By default, OSS escapes the forward slashes (/) in the object key when generating a presigned URL. This makes the generated URL unusable.
# Set slash_safe to True to prevent OSS from escaping the forward slashes (/), which allows the generated presigned URL to be used directly.
url = bucket.sign_url('PUT', object_name, expire_time, slash_safe=True, headers=headers)
return url
Go
package main
import (
"fmt"
"net/http"
"os"
"log"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func getURL() string {
// Set endpoint to the endpoint of your bucket's region. For China (Hangzhou), set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. For other regions, specify the actual endpoint.
endpoint := "https://oss-cn-hangzhou.aliyuncs.com"
// Replace "examplebucket" with your bucket name.
bucketName := "examplebucket"
// Replace "exampledir/exampleobject.txt" with the full object key. The object key cannot contain the bucket name.
objectName := "exampledir/exampleobject.txt"
// Check whether the environment variables are configured.
if endpoint == "" || bucketName == "" {
log.Fatal("Please set yourEndpoint and bucketName.")
}
// Obtain access credentials from environment variables. Before you run this sample code, make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables are configured.
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
handleError(err)
}
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// Set the signature version.
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New(endpoint, "", "", clientOptions...)
if err != nil {
fmt.Println("json err:", err)
}
bucket, err := client.Bucket(bucketName)
if err != nil {
fmt.Println("json err:", err)
}
options := []oss.Option{
oss.ContentType("image/png"),
}
signedURL, err := bucket.SignURL(objectName, oss.HTTPPut, 60, options...)
if err != nil {
fmt.Println("json err:", err)
}
return signedURL
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "templates/index.html")
return
} else if r.URL.Path == "/get_presigned_url_for_oss_upload" {
url := getURL()
fmt.Fprintf(w, "%s", url)
return
}
http.NotFound(w, r)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
Ruby
require 'sinatra'
require 'base64'
require 'open-uri'
require 'cgi'
require 'openssl'
require 'json'
require 'sinatra/reloader'
require 'sinatra/content_for'
require 'aliyun/oss'
include Aliyun::OSS
# Set the path of the public folder to the templates folder in the current directory.
set :public_folder, File.dirname(__FILE__) + '/templates'
# Get the ALIBABA_CLOUD_ACCESS_KEY_ID from an environment variable.
$access_key_id = ENV['ALIBABA_CLOUD_ACCESS_KEY_ID']
# Get the ALIBABA_CLOUD_ACCESS_KEY_SECRET from an environment variable.
$access_key_secret = ENV['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
# Specify the full object key, for example, exampledir/exampleobject.png. The object key cannot contain the bucket name.
object_key = 'exampledir/exampleobject.png'
def get_presigned_url(client, object_key)
# Replace <YOUR-BUCKET> with the bucket name.
bucket = client.get_bucket('<YOUR-BUCKET>')
# Generate a presigned URL and set its validity period to 3,600 seconds. The maximum validity period is 32,400 seconds.
bucket.object_url(object_key, 3600)
end
client = Aliyun::OSS::Client.new(
# Replace <YOUR-ENDPOINT> with the endpoint of your bucket's region. For the China (Hangzhou) region, the endpoint is https://oss-cn-hangzhou.aliyuncs.com.
endpoint: '<YOUR-ENDPOINT>',
# Obtain access credentials from environment variables. Before you run this sample code, make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables are configured.
access_key_id: $access_key_id,
access_key_secret: $access_key_secret
)
if ARGV.length == 1
$server_port = ARGV[0]
elsif ARGV.length == 2
$server_ip = ARGV[0]
$server_port = ARGV[1]
end
$server_ip = "0.0.0.0"
$server_port = 8000
puts "App server is running on: http://#{$server_ip}:#{$server_port}"
get '/get_presigned_url_for_oss_upload' do
url = get_presigned_url(client, object_key.to_s)
puts "Token: #{url}"
url
end
get '/*' do
puts "********************* GET "
send_file File.join(settings.public_folder, 'index.html')
end
C#
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using System.IO;
using System;
using Microsoft.Extensions.Logging;
using Aliyun.OSS;
namespace YourNamespace
{
public class Program
{
private ILogger<Program> _logger;
// Configure the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable.
public string AccessKeyId { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
// Configure the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable.
public string AccessKeySecret { get; set; } = Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Replace <YOUR-ENDPOINT> with the endpoint of your bucket's region. For the China (Hangzhou) region, the endpoint is https://oss-cn-hangzhou.aliyuncs.com.
private string EndPoint { get; set; } = "<YOUR-ENDPOINT>";
// Replace <YOUR-BUCKET> with the bucket name.
private string BucketName { get; set; } = "<YOUR-BUCKET>";
private string ObjectName { get; set; } = "exampledir/exampleobject2.png";
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Add logs.
builder.Logging.AddConsole();
var logger = builder.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
app.UseStaticFiles(); // Add this line to enable the static file middleware.
app.MapGet("/", async (context) =>
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "templates/index.html");
var htmlContent = await File.ReadAllTextAsync(filePath);
await context.Response.WriteAsync(htmlContent);
// Print logs.
logger.LogInformation("GET request to root path");
});
app.MapGet("/get_presigned_url_for_oss_upload", async (context) =>
{
var program = new Program(logger);
var signedUrl = program.GetSignedUrl();
logger.LogInformation($"SignedUrl: {signedUrl}"); // Log the signed URL.
await context.Response.WriteAsync(signedUrl);
});
app.Run();
}
// Inject ILogger through the constructor.
public Program(ILogger<Program> logger)
{
_logger = logger;
}
private string GetSignedUrl()
{
// Create an OSSClient instance.
var ossClient = new OssClient(EndPoint, AccessKeyId, AccessKeySecret);
// Generate a presigned URL.
var generatePresignedUriRequest = new GeneratePresignedUriRequest(BucketName, ObjectName, SignHttpMethod.Put)
{
Expiration = DateTime.Now.AddHours(1),
ContentType = "image/png"
};
var signedUrl = ossClient.GeneratePresignedUri(generatePresignedUriRequest);
return signedUrl.ToString();
}
}
}
Client-side sample code
The following example shows how to use a presigned URL to upload a file from a web client to OSS:
const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
event.preventDefault();
const fileInput = document.querySelector("#file");
const file = fileInput.files[0];
fetch("/get_presigned_url_for_oss_upload", { method: "GET" })
.then((response) => {
if (!response.ok) {
throw new Error("Failed to get the presigned URL");
}
return response.text();
})
.then((url) => {
const formData = new FormData();
formData.append("file", file);
fetch(url, {
method: "PUT",
headers: new Headers({
"Content-Type": "image/png",
}),
body: file,
}).then((response) => {
if (!response.ok) {
throw new Error("Failed to upload the file to OSS");
}
console.log(response);
alert("File uploaded");
});
})
.catch((error) => {
console.error("An error occurred:", error);
alert(error.message);
});
});Related documentation
See GitHub Examples for complete code examples of authorizing temporary access with STS.
See GitHub Examples for complete code examples of authorizing temporary access with signed URLs.