All Products
Search
Document Center

Object Storage Service:Authorized third-party upload

Last Updated:Apr 11, 2024

This topic describes how to use a signed URL or temporary access credentials from Security Token Service (STS) to grant a third-party user the permissions to directly upload objects to Object Storage Service (OSS).

Background information

In a standard client/server system architecture, the server is responsible for receiving and processing requests from the client, and OSS is used as a backend storage service. In that case, the client sends the objects to upload to the application server. Then, the server forwards the objects to OSS. In this process, objects are transmitted twice: from the client to the server and from the server to OSS. In the case of bursts of access requests, the server must provide sufficient bandwidth resources for multiple clients to upload objects simultaneously. This presents a challenge to the architecture scalability.

To address the challenge in the preceding scenario, OSS allows you to authorize third-party upload. This way, each client can directly upload objects to OSS without transmitting them to the server. This reduces the costs of application servers and maximizes the OSS capability to process large amounts of data. This way, you can focus on your business without worries about bandwidth and concurrency limits. Currently, you can grant third-party users the permissions to upload objects to OSS by using temporary access credentials from STS or a signed URL.

Method comparison

Method

Description

Scenario

Use temporary access credentials to authorize third-party users to upload objects to OSS

When a user or an application needs to access your OSS resources, you can issue temporary access credentials with specific permissions. The temporary access credentials consist of an AccessKey pair and a security token. The AccessKey pair consists of an AccessKey ID and an AccessKey secret. You can use temporary access credentials to grant users the permissions to upload objects to OSS within a specific period of time.

Authorize third-party applications to access specific resources or restrict the permissions of RAM users

Use a signed URL to authorize third-party users to upload objects to OSS

A signed URL is a pre-signed HTTP(s) URL that contains information, such as the operations to perform on an OSS object and the validity period. After you provide the signed URL to a third party, the third party can use the URL to directly upload an object to a specific OSS bucket without exposing the long-term Access Key pair.

Users want to directly upload objects to OSS in a web application, or allow anonymous users to upload objects, but need to control the upload time and object name.

Use temporary access credentials to authorize third-party users to upload objects to OSS

In most object upload scenarios, we recommend that you use Security Token Service (STS) SDKs to obtain temporary access credentials on the application server, and then use the temporary access credentials and OSS SDKs to upload objects from the client directly to OSS. The client can reuse the temporary access credentials on the application server to generate a signature. This is suitable for scenarios in which multipart upload and resumable upload are used to upload large objects. However, frequent calls to STS may cause throttling. In this case, we recommend that you cache the temporary access credentials and renew them before the validity period ends. For more information, see What is STS?

  1. Obtain temporary access credentials.

    The temporary access credentials consist of an AccessKey pair and a security token. The AccessKey pair consists of an AccessKey ID and an AccessKey secret. The validity period of temporary access credentials is in seconds. The minimum validity period of temporary access credentials is 900 seconds. The maximum validity period of temporary access credentials is the maximum session duration specified for the current role. For more information, see Specify the maximum session duration for a RAM role.

    You can use one of the following methods to obtain temporary access credentials:

    • Method 1:

      Call the AssumeRole operation to obtain temporary access credentials.

    • Method 2:

      Use STS SDKs to obtain temporary access credentials. For more information, see STS SDK overview.

  2. Use temporary access credentials to authorize a third-party user to upload objects.

    The following sample code provides examples on how to use temporary access credentials to authorize a third-party user to upload an object to OSS by using OSS SDKs for common programming languages. For more information about how to perform this operation by using OSS SDKs for other programming languages, see Overview.

    Java

    import com.aliyun.oss.*;
    import com.aliyun.oss.model.PutObjectRequest;
    import com.aliyun.oss.common.auth.*;
    import java.io.File;
    
    public class Demo {
        public static void main(String[] args) throws Throwable {
            // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
            String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, and OSS_SESSION_TOKEN environment variables are configured. 
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // Specify the name of the bucket. Example: examplebucket. 
            String bucketName = "examplebucket";
            // Specify the full path of the object. Example: exampleobject.txt. Do not include the bucket name in the full path. 
            String objectName = "exampleobject.txt";
            // Specify the full path of the local file. 
            String pathName = "D:\\examplefile.txt";
    
            // Create an OSSClient instance. 
            OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
    
            try {
                // Specify the full path of the local file. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
                PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(pathName));
                ossClient.putObject(putObjectRequest);
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("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();
                }
            }
        }
    }

    PHP

    <?php
    if (is_file(__DIR__ . '/../autoload.php')) {
        require_once __DIR__ . '/../autoload.php';
    }
    if (is_file(__DIR__ . '/../vendor/autoload.php')) {
        require_once __DIR__ . '/../vendor/autoload.php';
    }
    
    use OSS\OssClient;
    use OSS\Core\OssException;
    
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, and OSS_SESSION_TOKEN environment variables are configured. 
    $accessKeyId = getenv("OSS_ACCESS_KEY_ID");
    $accessKeySecret = getenv("OSS_ACCESS_KEY_SECRET");
    $securityToken = getenv("OSS_SESSION_TOKEN");
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    $endpoint = "yourEndpoint";
    // Specify the name of the bucket. 
    $bucket= "examplebucket";
    // Specify the full path of the object. Do not include the bucket name in the full path of the object. 
    $object = "exampleobject.txt";
    // Specify the string that you want to upload as an object. 
    $content = "Hello OSS";
    
    try {
        $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken);
        // Upload the string to the object by using the temporary access credentials obtained from STS. 
        $ossClient->putObject($bucket, $object, $content);
    } catch (OssException $e) {
        print $e->getMessage();
    }           

    Node.js

    const axios = require("axios");
    const OSS = require("ali-oss");
    
    // Use the temporary access credentials to initialize an OSSClient instance on the client. The instance is used to authorize temporary access to OSS resources. 
    const getToken = async () => {
      // Specify the address that is used by the client to obtain the temporary access credentials. 
      await axios.get("http://localhost:8000/sts").then((token) => {
        const client = new OSS({
           // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to oss-cn-hangzhou. 
          region: 'oss-cn-hangzhou',
          accessKeyId: token.data.AccessKeyId,
          accessKeySecret: token.data.AccessKeySecret,
          stsToken: token.data.SecurityToken,
          // Specify the name of the bucket. 
          bucket: "examplebucket",
          // Refresh the temporary access credentials. 
          refreshSTSToken: async () => {
            const refreshToken = await axios.get("http://localhost:8000/sts");
            return {
              accessKeyId: refreshToken.AccessKeyId,
              accessKeySecret: refreshToken.AccessKeySecret,
              stsToken: refreshToken.SecurityToken,
            };
          },
        });
        // Use the temporary access credentials to upload objects to OSS. 
        // Specify the full path of the object. Do not include the bucket name in the full path. Example: exampleobject.jpg. 
        // Specify the full path of the local file. Example: D:\\example.jpg. 
        client.put('exampleobject.jpg', 'D:\\example.jpg').then((res)=>{console.log(res)}).catch(e=>console.log(e))
      });
    };
    getToken()

    Python

    # -*- coding: utf-8 -*-
    import oss2
    from oss2.credentials import EnvironmentVariableCredentialsProvider
    
    # Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    endpoint = 'https://oss-cn-hangzhou.aliyuncs.com'
    # Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, and OSS_SESSION_TOKEN environment variables are configured. 
    auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
    # Specify the name of the bucket. 
    bucket_name = 'examplebucket'
    # Specify the full path of the object and the string that you want to upload. Do not include the bucket name in the full path. 
    object_name = 'exampleobject.txt'
    
    # Initialize the bucket based on the StsAuth instance. 
    bucket = oss2.Bucket(auth, endpoint, bucket_name)
    
    # Upload the object. 
    result = bucket.put_object(object_name, "hello world")
    print(result.status)

    Go

    package main
    
    import (
        "fmt"
        "github.com/aliyun/aliyun-oss-go-sdk/oss"
        "os"
    )
    
    func main() {
        // Obtain temporary access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, and OSS_SESSION_TOKEN environment variables are configured. 
        provider, err := oss.NewEnvironmentVariableCredentialsProvider()
        if err != nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        // Create an OSSClient instance. 
        // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. Specify your actual endpoint. 
        client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
        if err != nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        // Specify the name of the bucket. Example: examplebucket. 
        bucketName := "examplebucket"
        // Specify the full path of the object. Do not include the bucket name in the full path. Example: exampledir/exampleobject.txt. 
        objectName := "exampledir/exampleobject.txt"
        // Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. 
        filepath := "D:\\localpath\\examplefile.txt"
        bucket,err := client.Bucket(bucketName)
        // Use the temporary access credentials obtained from STS to grant the third-party user permissions to upload objects. 
        err = bucket.PutObjectFromFile(objectName,filepath)
        if err != nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        fmt.Println("upload success")
    }

Use a signed URL to authorize third-party users to upload objects to OSS

For simple object upload scenarios, you can use OSS SDKs on the application server to obtain a signed URL that is required to call the PutObject operation. Then, the client can use the signed URL to upload an object without using OSS SDKs. This solution is not suitable for multipart upload and resumable upload. The application server generates a signed URL for each part and returns the signed URL to the client. This increases the number of interactions with the application server and the complexity of network requests. In addition, the client may modify the content or order of the parts, which results in an invalid combined object. For more information, see Create a signed URL by using signature V1.

Important

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 upload and download, 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.

Use OSS SDKs

The following sample code provides examples on how to use a signed URL to authorize a third-party user to upload an object to OSS by using OSS SDKs for common programming languages. For more information about how to perform this operation by using OSS SDKs for other programming languages, see Overview.

Java

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.StorageClass;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.Date;

public class Demo {
    public static void main(String[] args) throws Throwable {
        // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the name of the bucket. Example: examplebucket. 
        String bucketName = "examplebucket";
        // Specify the full path of the object. Example: exampleobject.txt. Do not include the bucket name in the full path. 
        String objectName = "exampleobject.txt";
        // Specify the full path of the local file that you want to upload. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
        String pathName = "D:\\localpath\\examplefile.txt";

        // Create an OSSClient instance.
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
        
        // Specify request headers. 
        Map<String, String> headers = new HashMap<String, String>();
        /*// Specify the storage class of the object. 
        headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
        // Specify the content type. 
        headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/

        // Specify custom metadata. 
        Map<String, String> userMetadata = new HashMap<String, String>();
        /*userMetadata.put("key1","value1");
        userMetadata.put("key2","value2");*/

        URL signedUrl = null;
        try {
            // Specify the validity period of the signed URL. Unit: milliseconds. In this example, the validity period is set to 1 hour. 
            Date expiration = new Date(new Date().getTime() + 3600 * 1000L);

            // Generate the signed URL. 
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
            // Specify the expiration time. 
            request.setExpiration(expiration);

            // Add the headers to the request. 
            request.setHeaders(headers);
            // Specify custom metadata. 
            request.setUserMetadata(userMetadata);

            // Generate a signed URL that allows HTTP PUT requests. 
            signedUrl = ossClient.generatePresignedUrl(request);
            // Display the signed URL. 
            System.out.println("signed url for putObject: " + signedUrl);

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("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());
        }

        // Use the signed URL to authorize users to upload the object. In this example, HttpClients is used. 
        putObjectWithHttp(signedUrl, pathName, headers, userMetadata);
    }

    public static void putObjectWithHttp(URL signedUrl, String pathName, Map<String, String> headers, Map<String, String> userMetadata) throws IOException {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            HttpPut put = new HttpPut(signedUrl.toString());
            HttpEntity entity = new FileEntity(new File(pathName));
            put.setEntity(entity);
            // If you configure headers such as the user metadata and storage class when a signed URL is generated, these headers must be sent to the server when the signed URL is used to upload the local file. If headers for the signature are inconsistent with those sent to the server, a signature error is reported. 
            for(Map.Entry header: headers.entrySet()){
                put.addHeader(header.getKey().toString(),header.getValue().toString());
            }
            for(Map.Entry meta: userMetadata.entrySet()){
                // If userMeta is used, the x-oss-meta- prefix is added to userMeta. If you use other methods to generate a signed URL, the x-oss-meta- prefix is also added to userMeta. 
                put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
            }

            httpClient = HttpClients.createDefault();

            response = httpClient.execute(put);

            System.out.println("Upload status code:"+response.getStatusLine().getStatusCode());
            if(response.getStatusLine().getStatusCode() == 200){
                System.out.println("The object is uploaded by using the network library.");
            }
            System.out.println(response.toString());
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            response.close();
            httpClient.close();
        }
    }
}       

PHP

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Http\RequestCore;
use OSS\Http\ResponseCore;

// Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
$accessKeyId = getenv("OSS_ACCESS_KEY_ID");
$accessKeySecret = getenv("OSS_ACCESS_KEY_SECRET");
// Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
$endpoint = "yourEndpoint";
// Specify the name of the bucket. 
$bucket= "examplebucket";
// Specify the full path of the object. Do not include the bucket name in the full path of the object. 
$object = "exampleobject.txt";
// Set the validity period of the signed URL to 3,600 seconds. 
$timeout = 3600;
try {
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false);

    // Generate the signed URL. 
    $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT");
} catch (OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": signedUrl: " . $signedUrl . "\n");               

Node.js

const OSS = require("ali-oss");
const { default: axios } = require("axios");
const fs = require("fs");

const client = new OSS({
  // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to oss-cn-hangzhou. 
  region: 'yourregion',
  // Obtain access credentials from environment variables. Before you run the sample code, make sure that you have configured environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET. 
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // Specify the name of the bucket. 
  bucket: 'examplebucket',
});

// Generate a signed URL for the object. 
const url = client.signatureUrl("examplefile.txt", {
  method: "PUT",
  "Content-Type": "application/x-www-form-urlencoded",
});

// Specify the full path of the local file. 
const file = fs.readFileSync("D:\\localpath\\examplefile.txt");

// Use the signed URL to upload the object. 
axios({
  url,
  method: "PUT",
  data: file,
})
  .then((r) => console.log(r))
  .catch((e) => console.log(e));

Python

# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
import requests

# Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())

# Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
# Specify the name of the bucket. Example: examplebucket. 
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')
# Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
object_name = 'exampledir/exampleobject.txt'

# Specify headers. 
headers = dict()
# Specify the Content-Type parameter. 
# headers['Content-Type'] = 'text/txt'
# Specify the storage class. 
# headers["x-oss-storage-class"] = "Standard"

# Generate a signed URL that is used to upload the object. Set the validity period of the URL to 60 seconds. 
# By default, OSS identifies forward slashes (/) in the full path of an object as escape characters when a signed URL is generated. Therefore, the signed URL cannot be directly used. 
# Set the slash_safe parameter to True. This way, OSS does not identify forward slashes (/) in the full path of the object as escape characters. In this case, you can use the generated signed URL to upload the object. 
url = bucket.sign_url('PUT', object_name, 60, slash_safe=True, headers=headers)
print('Signed URL:', url)

# Use the signed URL to upload an object. In this example, requests is used. 
# Specify the full path of the local file. Example: D:\\exampledir\\examplefile.txt. 
requests.put(url, data=open('D:\\exampledir\\examplefile.txt', 'rb').read(), headers=headers)      

Go

package main

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

func HandleError(err error) {
    fmt.Println("Error:", err)
    os.Exit(-1)
}

func main() {
	// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}
	// Create an OSSClient instance. 
	// Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. Specify your actual endpoint. 
	client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}
    // Specify the name of the bucket. Example: examplebucket. 
    bucketName := "examplebucket"
    // Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path. 
    objectName := "exampledir/exampleobject.txt"
    bucket, err := client.Bucket(bucketName)
    if err != nil {
        HandleError(err)
    }
    // Generate a signed URL with a specified validity period for uploading the object. In this example, the validity period of the URL is 60 seconds. 
    signedURL, err := bucket.SignURL(objectName, oss.HTTPPut, 60)
    if err != nil {
        HandleError(err)
    }

    // To use a signed URL that contains custom parameters to access an object from a browser, make sure that the value of the ContentType parameter contained in the URL is the same as the ContentType value specified in the request. 
    options := []oss.Option{
        oss.Meta("myprop", "mypropval"),
        oss.ContentType("text/plain"),
    }
    
    signedURL, err = bucket.SignURL(objectName, oss.HTTPPut, 60, options...)
    if err != nil {
        HandleError(err)
    }
    fmt.Printf("Sign Url:%s\n", signedURL)
}