tencent cloud

Server Signature Practice
Last updated: 2025-09-19 10:43:54
Server Signature Practice
Last updated: 2025-09-19 10:43:54
Documentation introduction on how to set up a secure temporary signature service.

Solution Strength

Permission security: It can effectively limit the scope of security permissions and can only be used to upload a specified file path.
Path security: The random COS file path is determined by the server, which can effectively avoid the problem of existing files being overwritten and security risks.
Transmission security: Generate the signature on the server to avoid the risk of temporary key leakage during transmission.

Upload Process

1. Select a file on the client, and the client will send the original file name to the server.
2. The server generates a random COS file path with time based on the file extension, applies for corresponding permissions, and returns the signature information and COS key to the front end.

Setting Up a Temporary Signature Service

Temporary Access Credentials are restricted-permission keys obtained through the TencentCloud API provided by CAM. When initiating a COS API request, the three fields TmpSecretId, TmpSecretKey, and Token in the returned information from the temporary key API are required to calculate the signature.
When requesting a server signature, first obtain a temporary key, then use it to generate the signature and return it to the client.
The following example code in languages:
Node.js
Go
PHP
Python
Java
.NET(C#)
Complete code can be found in Sample Code.
// Temporary key service example
var express = require('express');
var crypto = require('crypto');
var moment = require('moment');
var STS = require('qcloud-cos-sts');
const url = require('url');
const { log } = require('console');

// config
var config = {
// Get Tencent Cloud Key, recommend using a Sub-user key with limited permissions https://console.tencentcloud.com/cam/capi
secretId: process.env.COS_SECRET_ID,
secretKey: process.env.COS_SECRET_KEY,
// key validity period
durationSeconds: 1800,
// fill in the bucket and region here, for example: test-1250000000, ap-guangzhou
bucket: process.env.PERSIST_BUCKET,
region: process.env.PERSIST_BUCKET_REGION
};

// get temporary key
var getTempCredential = async function(cosKey){
var shortBucketName = config.bucket.substr(0 , config.bucket.lastIndexOf('-'));
var appId = config.bucket.substr(1 + config.bucket.lastIndexOf('-'));
// Start getting temporary key
var policy = {
"version": "2.0",
"statement": [
{
"action": [
// Upload operation required
"name/cos:PutObject"
],
"effect": "allow",
"resource": [
// Only cosKey resource
'qcs::cos:' + config.region + ':uid/' + appId + ':prefix//' + appId + '/' + shortBucketName + '/' + cosKey,
]
}
]
};
let tempKeys = null;
try{
tempKeys = await STS.getCredential({
secretId: config.secretId,
secretKey: config.secretKey,
durationSeconds: config.durationSeconds,
policy: policy,
});
console.log(tempKeys);
return tempKeys;
} catch(err){
console.log(err);
res.send(JSON.stringify(err));
return null;
}
};

// Calculate the signature.
var getSignature = function(tempCredential, httpMethod, cosHost, pathname) {
const signAlgorithm = 'sha1';
const credentials = tempCredential.credentials;
const keyTime = `${tempCredential.startTime};${tempCredential.expiredTime}`;

// step 1: generate SignKey
var signKey = crypto.createHmac(signAlgorithm, credentials.tmpSecretKey).update(keyTime).digest('hex');
console.log("signKey:"+signKey);

// step two: generate StringToSign
const httpString = `${httpMethod.toLowerCase()}\\n/${pathname}\\n\\nhost=${cosHost}\\n`;
console.log("httpString:"+httpString);
const httpStringHash = crypto.createHash(signAlgorithm).update(httpString).digest('hex');
const stringToSign = `${signAlgorithm}\\n${keyTime}\\n${httpStringHash}\\n`;
console.log("stringToSign:"+stringToSign);

// step three: generate Signature
var signature = crypto.createHmac(signAlgorithm, signKey).update(stringToSign).digest('hex');
console.log("signature:"+signature);

// step four: generate authorization
let authorization = `q-sign-algorithm=${signAlgorithm}&
q-ak=${credentials.tmpSecretId}&
q-sign-time=${keyTime}&
q-key-time=${keyTime}&
q-header-list=host&q-url-param-list=&q-signature=${signature}`;

// Remove \\n caused by line breaks above
authorization = authorization.replace(/\\n/g, '');
console.log("authorization:"+authorization);
return authorization;
}

// Create a temporary key service and a static service for debug
var app = express();
// Signature interface for direct upload
app.all('/sts-server-sign', async function (req, res, next) {
// Get the field to be signed
var httpMethod = req.query.httpMethod;
var cosHost = req.query.host;
var cosKey = req.query.cosKey;

console.log(httpMethod + " " + cosHost + " " + cosKey);

cosHost = decodeURIComponent(cosHost);
cosKey = decodeURIComponent(cosKey);

console.log(httpMethod + " " + cosHost + " " + cosKey);

// Check for anomalies
if (!config.secretId || !config.secretKey) return res.send({ code: '-1', message: 'secretId or secretKey not ready' });
if (!config.bucket || !config.region) return res.send({ code: '-1', message: 'bucket or regions not ready' });
if (!httpMethod || !cosHost || !cosKey) return res.send({ code: '-1', message: 'httpMethod or host or coskey is not empty' });

// Start getting temporary key
var tempCredential = await getTempCredential(cosKey);
if(!tempCredential){
res.send({ code: -1, message: 'get temp credentials fail' });
return;
}

// Calculate the signature with temporary key
let authorization = getSignature(tempCredential, httpMethod, cosHost, cosKey);

// Return domain name, file path, signature, credentials
res.send({
code: 0,
data: {
cosHost: cosHost,
cosKey: cosKey,
authorization: authorization,
securityToken: tempCredential.credentials.sessionToken
},
});
});

app.all('*', function (req, res, next) {
res.send({ code: -1, message: '404 Not Found' });
});

// Start the signature service
app.listen(3000);
console.log('app is listening at http://127.0.0.1:3000');

Complete code can be found in Sample Code.
package main

import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/tencentyun/cos-go-sdk-v5"
sts "github.com/tencentyun/qcloud-cos-sts-sdk/go"
"math/rand"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"time"
"unicode"
)

type Config struct {
filename string
appId string
SecretId string
SecretKey string
Proxy string
DurationSeconds int
Bucket string
Region string
AllowActions []string
}

type Permission struct {
LimitExt bool `json:"limitExt"`
ExtWhiteList []string `json:"extWhiteList"`
LimitContentType bool `json:"limitContentType"`
LimitContentLength bool `json:"limitContentLength"`
}

func generateCosKey(ext string) string {
date := time.Now()
m := int(date.Month()) + 1
ymd := fmt.Sprintf("%d%02d%d", date.Year(), m, date.Day())
r := fmt.Sprintf("%06d", rand.Intn(1000000))
cosKey := fmt.Sprintf("file/%s/%s_%s.%s", ymd, ymd, r, ext)
return cosKey
}

func getPermission() Permission {
permission := Permission{
LimitExt: true,
ExtWhiteList: []string{"jpg", "jpeg", "png", "gif", "bmp"},
LimitContentType: false,
LimitContentLength: false,
}
return permission
}

func getConfig() Config {
config := Config{
filename: "test.jpg",
appId: "12500000000",
SecretId: os.Getenv("SECRETID"), // User's SecretId, recommend using sub-account keys, adhere to the principle of least privilege to reduce use risk. To obtain sub-account key, see https://www.tencentcloud.com/document/product/598/37140?from_cn_redirect=1
SecretKey: os.Getenv("SECRETKEY"), // User's SecretKey, recommend using sub-account keys, adhere to the principle of least privilege to reduce use risk. To obtain sub-account key, see https://www.tencentcloud.com/document/product/598/37140?from_cn_redirect=1
Proxy: os.Getenv("Proxy"),
DurationSeconds: 1800,
Bucket: "0-1253960454",
Region: "ap-guangzhou",
AllowActions: []string{
"name/cos:PutObject",
},
}
return config
}

func stringInSlice(str string, list []string) bool {
for _, v := range list {
if v == str {
return true
}
}
return false
}

func StructToCamelMap(input interface{}) map[string]interface{} {
v := reflect.ValueOf(input)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}

result := make(map[string]interface{})
typ := v.Type()

for i := 0; i < v.NumField(); i++ {
field := typ.Field(i)
fieldValue := v.Field(i)

// Convert field name to lower camel case
key := toLowerCamel(field.Name)

// Handle nested structure
if fieldValue.Kind() == reflect.Struct ||
(fieldValue.Kind() == reflect.Ptr && fieldValue.Elem().Kind() == reflect.Struct) {

if fieldValue.IsNil() && fieldValue.Kind() == reflect.Ptr {
result[key] = nil
continue
}

result[key] = StructToCamelMap(fieldValue.Interface())
} else {
// Handle basic type
result[key] = fieldValue.Interface()
}
}

return result
}

// Convert to lower camel case (first letter lowercase)
func toLowerCamel(s string) string {
if s == "" {
return s
}

// Handle all caps words (for example ID)
if strings.ToUpper(s) == s {
return strings.ToLower(s)
}

// Switch to lower camel case
runes := []rune(s)
runes[0] = unicode.ToLower(runes[0])
return string(runes)
}

func getStsCredential() (map[string]interface{}, error) {
config := getConfig()

permission := getPermission()

c := sts.NewClient(
// Get key through environment variables, os.Getenv method means get environment variables
config.SecretId, //os.Getenv("SECRETID"), // User's SecretId, recommend using sub-account keys, follow the principle of least privilege to reduce use risk. To obtain sub-account key, see https://www.tencentcloud.com/document/product/598/37140?from_cn_redirect=1
config.SecretKey, //os.Getenv("SECRETKEY"), // User's SecretKey, recommend using sub-account keys, adhere to the principle of least privilege to reduce use risk. To obtain sub-account key, see https://www.tencentcloud.com/document/product/598/37140?from_cn_redirect=1
nil,
// sts.Host("sts.internal.tencentcloudapi.com"), // Set domain name, default domain sts.tencentcloudapi.com
// sts.Scheme("http"), // Set protocol. Default is https. Public cloud STS cannot use http. Set http only in special scenarios.
)

condition := make(map[string]map[string]interface{})

segments := strings.Split(config.filename, ".")
if len(segments) == 0 {
//ext := ""
}
ext := segments[len(segments)-1]

if permission.LimitExt {
extInvalid := ext == "" || !stringInSlice(ext, permission.ExtWhiteList)
if extInvalid {
return nil, errors.New("unauthorized file, upload prohibited")
}
}

if permission.LimitContentType {
condition["string_like_if_exist"] = map[string]interface{}{
// Only upload allowed with content-type as image/*
"cos:content-type": "image/*",
}
}

// 3. Limit upload file size
if permission.LimitContentLength {
condition["numeric_less_than_equal"] = map[string]interface{}{
// Upload size limit cannot exceed 5MB (effective for simple upload only)
"cos:content-length": 5 * 1024 * 1024,
}
}

key := generateCosKey(ext)
// Policy overview https://www.tencentcloud.com/document/product/436/18023?from_cn_redirect=1
opt := &sts.CredentialOptions{
DurationSeconds: int64(config.DurationSeconds),
Region: config.Region,
Policy: &sts.CredentialPolicy{
Version: "2.0",
Statement: []sts.CredentialPolicyStatement{
{
// Permission list for keys. Simple upload and sharding require the following permissions. For other permission lists, see https://www.tencentcloud.com/document/product/436/31923?from_cn_redirect=1
Action: config.AllowActions,
Effect: "allow",
Resource: []string{
// Change to the allowed path prefix. The specific path for upload can be selected based on your website's user login status, for example: a.jpg or a/* or * (using wildcard * poses significant security risks, please be cautious when considering using)
// The bucket naming format is BucketName-APPID, the bucket filled here must be in this format
"qcs::cos:ap-guangzhou:uid/" + config.appId + ":" + config.Bucket + "/" + key,
},
// Start building the effective condition condition
// For setting rules about condition and COS-supported condition types, see https://www.tencentcloud.com/document/product/436/71306?from_cn_redirect=1
Condition: condition,
},
},
},
}

// case 1 request temporary key
res, err := c.GetCredential(opt)
if err != nil {
return nil, err
}
// Convert to lower camel case map
resultMap := StructToCamelMap(res)
resultMap["bucket"] = config.Bucket
resultMap["region"] = config.Region
resultMap["key"] = key

return resultMap, nil
}

func main() {
result, err := getStsCredential()
if err != nil {
fmt.Printf("request temporary key fail: %v\\n", err)
return // determine whether to exit based on context
}

// Type assertion for credentials as map[string]interface{}
credentials, ok := result["credentials"].(map[string]interface{})
if !ok {
fmt.Println("Invalid credential format")
return
}
// Field acquisition with type checking
tak, tok := credentials["tmpSecretID"].(string)
tsk, tskok := credentials["tmpSecretKey"].(string)
token, tokenok := credentials["sessionToken"].(string)
if !tok || !tskok || !tokenok {
fmt.Println("Missing fields or type error in temporary credential")
return
}
host := "https://" + result["bucket"].(string) + ".cos." + result["region"].(string) + ".myqcloud.com"
u, _ := url.Parse(host)
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{})
name := result["key"].(string)
ctx := context.Background()
opt := &cos.PresignedURLOptions{
Query: &url.Values{},
Header: &http.Header{},
}
opt.Query.Add("x-cos-security-token", token)
signature := c.Object.GetSignature(ctx, http.MethodPut, name, "tak", "tsk", time.Hour, opt, true)
fmt.Printf("%s\\n%s\\n%s\\n%s\\n", tak, tsk, token, signature)
data := make(map[string]string)

// Add token and sign
data["securityToken"] = token
data["authorization"] = signature
data["cosHost"] = host
data["cosKey"] = name
// Convert to JSON
jsonData, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Println("JSON encoding failure:", err)
return
}
fmt.Println(string(jsonData))
}


Complete code can be found in Sample Code.
<?php
require_once __DIR__ . '/vendor/autoload.php';

use QCloud\\COSSTS\\Sts;

// Generate the COS file path Filename to upload
function generateCosKey($ext) {
$ymd = date('Ymd');
$r = substr('000000' . rand(), -6);
$cosKey = 'file/' . $ymd. '/' . $ymd . '_' . $r;
if ($ext) {
$cosKey = $cosKey . '.' . $ext;
}
return $cosKey;
};

// Get temporary key for single file upload permission
function getKeyAndCredentials($filename) {
// Business implements user login status verification, such as token validation
// $canUpload = checkUserRole($userToken);
// if (!$canUpload) {
// return 'Current user has no upload permission';
// }

// Control file upload types and size, enable on demand
$permission = array(
'limitExt' => false, // Restrict file extensions
'extWhiteList' => ['jpg', 'jpeg', 'png', 'gif', 'bmp'], // Restricted file extensions
'limitContentType' => false, // Restrict content types
'limitContentLength' => false, // Limit upload file size
);
$condition = array();

// The client passes the original file name, generate a random Key based on the file suffix
$ext = pathinfo($filename, PATHINFO_EXTENSION);

// 1. Limit file upload extensions
if ($permission['limitExt']) {
if ($ext === '' || array_key_exists($ext, $permission['extWhiteList'])) {
return 'unauthorized file, upload prohibited';
}
}

// 2. Limit file upload content-type
if ($permission['limitContentType']) {
// Only upload allowed with content-type as image/*
$condition['string_like_if_exist'] = array('cos:content-type' => 'image/*');
}

// 3. Limit upload file size
if ($permission['limitContentLength']) {
// Upload size limit cannot exceed 5MB (effective for simple upload only)
$condition['numeric_less_than_equal'] = array('cos:content-length' => 5 * 1024 * 1024);
}

$cosKey = generateCosKey($ext);
$bucket = 'test-125000000'; // Replace with your bucket
$region = 'ap-guangzhou'; // Replace with the park where the bucket resides
$config = array(
'url' => 'https://sts.tencentcloudapi.com/', // URL and domain should be consistent
'domain' => 'sts.tencentcloudapi.com', // Domain name, optional, defaults to sts.tencentcloudapi.com
'proxy' => '',
'secretId' => "",//getenv('GROUP_SECRET_ID'), // Fixed key. For plaintext key, fill in directly as 'xxx', do not use getenv() function
'secretKey' => "",//getenv('GROUP_SECRET_KEY'), // Fixed key. For plaintext key, fill in directly as 'xxx', do not use getenv() function
'bucket' => $bucket, // Replace with your bucket
'region' => $region, // Replace with the park where the bucket resides
'durationSeconds' => 1800, // key validity period
'allowPrefix' => array($cosKey), // Only allocate path permission for the current key
// Permission list for keys. Simple upload and sharding require the following permissions. For other permission lists, see https://www.tencentcloud.com/document/product/436/31923?from_cn_redirect=1
'allowActions' => array (
// Simple upload
'name/cos:PutObject'
),
);

if (!empty($condition)) {
$config['condition'] = $condition;
}

$sts = new Sts();
$tempKeys = $sts->getTempKeys($config);
$resTemp = array_merge(
$tempKeys,
[
'startTime' => time(),
'bucket' => $bucket,
'region' => $region,
'key' => $cosKey,
]
);
return $resTemp;
}

function getSign()
{
$filename = "test.jpg";
$method = "putObject";
$result = getKeyAndCredentials($filename);
$credentials = $result["credentials"];
$sessionToken = $credentials["sessionToken"];
$tmpSecretId = $credentials["tmpSecretId"];
$tmpSecretKey = $credentials["tmpSecretKey"];
$expiredTime = $result["expiredTime"];
$startTime = $result["startTime"];
$bucket = $result["bucket"];
$region = $result["region"];
$key = $result["key"];

$cosClient = new Qcloud\\Cos\\Client(
array(
'region' => $region,
'scheme' => 'https', // protocol header, defaults to http
'signHost' => true, //By default, sign the Header Host. You can also choose not to sign the Header Host, but this may cause request failure or security vulnerability. Set to false if not signing the host.
'credentials'=> array(
'secretId' => $tmpSecretId,
'secretKey' => $tmpSecretKey,
'token' => $sessionToken)));
### Upload pre-signiture by using the simple upload.
try {
$url = $cosClient->getPresignedUrl($method,array(
'Bucket' => $bucket,
'Key' => $key,
'Body' => "",
'Params'=> array('x-cos-security-token' => $sessionToken),
'Headers'=> array(),
), $expiredTime - $startTime); //Signature validity time

$parsedUrl = parse_url($url);
$host = 'https://' . $parsedUrl['host']; // automatically include port (if any)
$queryString = isset($parsedUrl['query']) ? $parsedUrl['query'] : '';
$queryParts = explode('&', $queryString);
$signParts = array_filter($queryParts, function($part) {
return strpos($part, 'x-cos-security-token=') !== 0;
});
$sign = implode('&', $signParts);
$result = [
'cosHost' => $host,
'cosKey' => $key,
'authorization' => $sign,
'securityToken' => $sessionToken
];

echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

} catch (\\Exception $e) {
//Request failed
echo($e);
}
}
getSign();
Complete code can be found in Sample Code.
#!/usr/bin/env python
# coding=utf-8
import json
import os
import datetime
import random
from urllib.parse import urlencode

from qcloud_cos import CosConfig, CosS3Client

from sts.sts import Sts


if __name__ == '__main__':

# config
config = {
"filename":"test.jpg",
"appId": "1250000000",
"secretId": os.getenv("SecretId"),
"secretKey": os.getenv("SecretKey"),
"proxy": os.getenv("Proxy"),
"durationSeconds": 1800,
"bucket": "0-1253960454",
"region": "ap-guangzhou",
# key upload permission list
"allowActions": [
# Simple upload
"name/cos:PutObject"
],
}

permission = {
"limitExt": True, # Restrict file extensions
"extWhiteList": ["jpg", "jpeg", "png", "gif", "bmp"], # Restricted file extensions
"limitContentType": False, # Limit uploading contentType
"limitContentLength": False, # Limit upload file size
}


# Generate the COS file path Filename to upload
def generate_cos_key(ext=None):
date = datetime.datetime.now()
ymd = date.strftime('%Y%m%d')
r = str(int(random.random() * 1000000)).zfill(6)
cos_key = f"file/{ymd}/{ymd}_{r}.{ext if ext else ''}"
return cos_key


segments = config['filename'].split(".")
ext = segments[-1] if segments else ""
key = generate_cos_key(ext)
resource = f"qcs::cos:{config['region']}:uid/{config['appId']}:{config['bucket']}/{key}"

condition = {}

# 1. Limit file upload extensions
if permission["limitExt"]:
ext_invalid = not ext or ext not in permission["extWhiteList"]
if ext_invalid:
print('Unauthorized file, upload prohibited')

# 2. Limit file upload content-type
if permission["limitContentType"]:
condition.update({
"string_like_if_exist": {
# Only upload allowed with content-type as image/*
"cos:content-type": "image/*"
}
})

# 3. Limit upload file size
if permission["limitContentLength"]:
condition.update({
"numeric_less_than_equal": {
# Upload size limit cannot exceed 5MB (effective for simple upload only)
"cos:content-length": 5 * 1024 * 1024
}
})


def get_credential_demo():
credentialOption = {
# Temporary key valid duration in seconds
'duration_seconds': config.get('durationSeconds'),
'secret_id': config.get("secretId"),
# fixed key
'secret_key': config.get("secretKey"),
# Replace with your bucket
'bucket': config.get("bucket"),
'proxy': config.get("proxy"),
# Replace with the bucket's located region
'region': config.get("region"),
"policy": {
"version": '2.0',
"statement": [
{
"action": config.get("allowActions"),
"effect": "allow",
"resource": [
resource
],
"condition": condition
}
],
},
}

try:

sts = Sts(credentialOption)
response = sts.get_credential()
credential_dic = dict(response)
credential_info = credential_dic.get("credentials")
credential = {
"bucket": config.get("bucket"),
"region": config.get("region"),
"key": key,
"startTime": credential_dic.get("startTime"),
"expiredTime": credential_dic.get("expiredTime"),
"requestId": credential_dic.get("requestId"),
"expiration": credential_dic.get("expiration"),
"credentials": {
"tmpSecretId": credential_info.get("tmpSecretId"),
"tmpSecretKey": credential_info.get("tmpSecretKey"),
"sessionToken": credential_info.get("sessionToken"),
},
}
return credential
except Exception as e:
print(e)


result = get_credential_demo()
credentials = result["credentials"]
secret_id = credentials["tmpSecretId"]
secret_key = credentials["tmpSecretKey"]
token = credentials["sessionToken"]
bucket = result["bucket"]
region = result["region"]
key = result["key"]
expired = result["expiredTime"]

config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token)
client = CosS3Client(config)
sign = client.get_auth(Method='put',Bucket=bucket, Key=key, Expired=expired, Params={
'x-cos-security-token': token
},SignHost=True)
sign = urlencode(dict([item.split('=', 1) for item in sign.split('&')]))
host = "https://" + result["bucket"] + ".cos." + result["region"] + ".myqcloud.com"
response = {
"cosHost":host,
"cosKey":key,
"authorization":sign,
"securityToken":token
}
print('get data : ' + json.dumps(response, indent=4))
Complete code can be found in Sample Code.
package com.tencent.cloud;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicSessionCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.region.Region;
import com.tencent.cloud.cos.util.Jackson;
import org.junit.Test;

import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

public class ServerSignTest {

public static String generateCosKey(String ext) {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
String ymd = dateFormat.format(date);

Random random = new Random();
int r = random.nextInt(1000000);
String rStr = String.format("%06d", r);

String cosKey = String.format("file/%s/%s_%s.%s", ymd, ymd, rStr, ext != null ? ext : "");
return cosKey;
}

// obtain configuration information
public TreeMap<String,Object> getConfig(){

String bucket = "0-1250000000";
String appId = "1250000000";
String filename = "test.jpg";
String region = "ap-guangzhou";
String secretId = "";
String secretKey = "";
String proxy = "";
int durationSeconds = 1800;

String[] segments = filename.split("\\\\.");
String ext = segments.length > 0 ? segments[segments.length - 1] : "";

// temporary key limit
Boolean limitExt = false; // Restrict file extensions
List extWhiteList = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp"); // Restricted file extensions
Boolean limitContentType = false; // Limit uploading contentType
Boolean limitContentLength = false; // Limit upload file size


Map<String, Object> condition = new HashMap();

// 1. Limit file upload extensions
if (limitExt) {
boolean extInvalid = ext == null || !extWhiteList.contains(ext);
if (extInvalid) {
System.out.println("Unauthorized file, upload prohibited");
return null;
}
}

// 2. Limit file upload content-type
if (limitContentType) {
condition.put("string_like_if_exist", new HashMap<String, String>() {{
put("cos:content-type", "image/*");
}});
}

// 3. Limit upload file size (only takes effect for simple upload)
if (limitContentLength) {
condition.put("numeric_less_than_equal", new HashMap<String, Long>() {{
put("cos:content-length", 5L * 1024 * 1024);
}});
}
String key = generateCosKey(ext);
String resource = "qcs::cos:" + region + ":uid/" + appId + ':' + bucket + '/' + key;
List allowActions = Arrays.asList(
// Simple upload
"name/cos:PutObject"
);

// Build policy
Map<String, Object> policy = new HashMap();
policy.put("version", "2.0");
Map<String, Object> statement = new HashMap();
statement.put("action", allowActions);
statement.put("effect", "allow");
List<String> resources = Arrays.asList(
resource
);
statement.put("resource", resources);
statement.put("condition", condition);
policy.put("statement", Arrays.asList(statement));


// Build config
TreeMap <String,Object> config = new TreeMap<String, Object>();
config.put("secretId",secretId);
config.put("secretKey",secretKey);
config.put("proxy",proxy);
config.put("duration",durationSeconds);
config.put("bucket",bucket);
config.put("region",region);
config.put("key",key);
config.put("policy",Jackson.toJsonPrettyString(policy));
return config;
}

public TreeMap <String,Object> getKeyAndCredentials() {
TreeMap config = this.getConfig();
try {
Response response = CosStsClient.getCredential(config);
TreeMap <String,Object> credential = new TreeMap<String, Object>();
TreeMap <String,Object> credentials = new TreeMap<String, Object>();
credentials.put("tmpSecretId",response.credentials.tmpSecretId);
credentials.put("tmpSecretKey",response.credentials.tmpSecretKey);
credentials.put("sessionToken",response.credentials.sessionToken);
credential.put("startTime",response.startTime);
credential.put("expiredTime",response.expiredTime);
credential.put("requestId",response.requestId);
credential.put("expiration",response.expiration);
credential.put("credentials",credentials);
credential.put("bucket",config.get("bucket"));
credential.put("region",config.get("region"));
credential.put("key",config.get("key"));
return credential;
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("no valid secret !");
}
}
/**
Basic temporary key application example, suitable for granting a set of operation permissions to multiple object paths in a bucket
*/
@Test
public void testGetKeyAndCredentials() {
TreeMap <String,Object> credential = this.getKeyAndCredentials();
TreeMap <String,Object> credentials = (TreeMap<String, Object>) credential.get("credentials");
try {


String tmpSecretId = (String) credentials.get("tmpSecretId");
String tmpSecretKey = (String) credentials.get("tmpSecretKey");
String sessionToken = (String) credentials.get("sessionToken");
Date expiredTime = new Date((Long) credential.get("expiredTime"));
String key = (String) credential.get("key");
String bucket = (String) credential.get("bucket");
String region = (String) credential.get("region");

COSCredentials cred = new BasicSessionCredentials(tmpSecretId, tmpSecretKey, sessionToken);
ClientConfig clientConfig = new ClientConfig();
clientConfig.setRegion(new Region(region));

COSClient cosClient = new COSClient(cred, clientConfig);


Map<String, String> headers = new HashMap<String,String>();
Map<String, String> params = new HashMap<String,String>();
params.put("x-cos-security-token",sessionToken);
URL url = cosClient.generatePresignedUrl(bucket, key, expiredTime, HttpMethodName.PUT, headers, params);
String host = "https://" + url.getHost();
String query = url.toString().split("\\\\?")[1];
String sign = query.split("&x-cos-security-token")[0];
TreeMap <String,Object> result = new TreeMap<String, Object>();
result.put("cosHost",host);
result.put("cosKey",key);
result.put("authorization",sign);
result.put("securityToken",sessionToken);
System.out.println(Jackson.toJsonPrettyString(result));
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("no valid sign !");
}
}
}
Complete code can be found in Sample Code.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Mail;
using COSSTS;
using COSXML;
using COSXML.Auth;
using COSXML.Model.Tag;
using Newtonsoft.Json;
using Formatting = System.Xml.Formatting;


namespace COSSnippet
{
public class ServerSign
{
//permanent key
string secretId = "";
string secretKey = "";

string bucket = "bucket-1250000000";
string appId = "1250000000";
string region = "ap-guangzhou";
string filename = "test.jpg";
string method = "put";
int time = 1800;
// limit
Boolean limitExt = false; // Restrict file extensions
List<string> extWhiteList = new List<String> { "jpg", "jpeg", "png", "gif", "bmp" }; // Restricted file extensions
Boolean limitContentType = false; // Limit uploading contentType
Boolean limitContentLength = false; // Limit upload file size

public string generateCosKey(string ext)
{
DateTime date = DateTime.Now;
int m = date.Month;
string ymd = $"{date.Year}{(m < 10 ? $"0{m}" : m.ToString())}{date.Day}";
Random random = new Random();
string r = random.Next(0, 1000000).ToString("D6"); // Generate a 6-digit random number with leading zeros
string cosKey = $"file/{ymd}/{ymd}_{r}.{(string.IsNullOrEmpty(ext) ? "" : ext)}";
return cosKey;
}
public Dictionary<string, object> getConfig()
{
Dictionary<string, object> config = new Dictionary<string, object>();
string[] allowActions = new string[] { // Allowed operation scope, using upload as an example
"name/cos:PutObject"
};
string[] segments = filename.Split(".");
string ext = segments.Length > 0 ? segments[segments.Length - 1] : string.Empty;
string key = generateCosKey(ext);
string resource = $"qcs::cos:{region}:uid/{appId}:{bucket}/{key}";

var condition = new Dictionary<string, object>();
// 1. Limit file upload extensions
if (limitExt)
{
var extInvalid = string.IsNullOrEmpty(ext) || !extWhiteList.Contains(ext);
if (extInvalid)
{
Console.WriteLine("Unauthorized file, upload prohibited");
return null;
}
}

// 2. Limit file upload content-type
if (limitContentType)
{
condition["string_like_if_exist"] = new Dictionary<string, string>
{
{ "cos:content-type", "image/*" } // Only upload allowed with content-type as image/*
};
}

// 3. Limit upload file size (only takes effect for simple upload)
if (limitContentLength)
{
condition["numeric_less_than_equal"] = new Dictionary<string, long>
{
{ "cos:content-length", 5 * 1024 * 1024 } // Upload size limit cannot exceed 5MB
};
}

var policy = new Dictionary<string, object>
{
{ "version", "2.0" },
{ "statement", new List<Dictionary<string, object>>
{
new Dictionary<string, object>
{
{ "action", allowActions },
{ "effect", "allow" },
{ "resource", new List<string>
{
resource,
}
},
{ "condition", condition }
}
}
}
};

// Serialize to JSON and output
string jsonPolicy = JsonConvert.SerializeObject(policy);
config.Add("bucket", bucket);
config.Add("region", region);
config.Add("durationSeconds", time);

config.Add("secretId", secretId);
config.Add("secretKey", secretKey);
config.Add("key", key);
config.Add("policy", jsonPolicy);
return config;
}
// Obtain temporary access credentials for federated identity https://www.tencentcloud.com/document/product/1312/48195?from_cn_redirect=1
public Dictionary<string, object> GetCredential()
{

var config = getConfig();
// get temporary key
Dictionary<string, object> credential = STSClient.genCredential(config);
Dictionary<string, object> credentials = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonConvert.SerializeObject((object) credential["Credentials"]));
Dictionary<string, object> credentials1 = new Dictionary<string, object>();
credentials1.Add("tmpSecretId",credentials["TmpSecretId"]);
credentials1.Add("tmpSecretKey",credentials["TmpSecretKey"]);
credentials1.Add("sessionToken",credentials["Token"]);
Dictionary<string, object> dictionary1 = new Dictionary<string, object>();
dictionary1.Add("credentials",credentials1);
dictionary1.Add("startTime",credential["StartTime"]);
dictionary1.Add("requestId",credential["RequestId"]);
dictionary1.Add("expiration",credential["Expiration"]);
dictionary1.Add("expiredTime",credential["ExpiredTime"]);
dictionary1.Add("bucket",config["bucket"]);
dictionary1.Add("region",config["region"]);
dictionary1.Add("key",config["key"]);
return dictionary1;
}
static void Main(string[] args)
{
ServerSign m = new ServerSign();
Dictionary<string, object> result = m.GetCredential();
Dictionary<string, object> credentials = (Dictionary<string, object>)result["credentials"];
string tmpSecretId = (string)credentials["tmpSecretId"];
string tmpSecretKey = (string)credentials["tmpSecretKey"];
string sessionToken = (string)credentials["sessionToken"];
string bucket = (string)result["bucket"];
string region = (string)result["region"];
string key = (string)result["key"];
long expiredTime = (long)result["expiredTime"];
int startTime = (int)result["startTime"];
QCloudCredentialProvider cosCredentialProvider = new DefaultSessionQCloudCredentialProvider(
tmpSecretId, tmpSecretKey, expiredTime, sessionToken);
CosXmlConfig config = new CosXmlConfig.Builder()
.IsHttps(true) //set default HTTPS request
.SetRegion(region) // Set a default bucket region.
.SetDebugLog(true) // Display log.
.Build(); // Create CosXmlConfig object.
CosXml cosXml = new CosXmlServer(config, cosCredentialProvider);
PreSignatureStruct preSignatureStruct = new PreSignatureStruct();
preSignatureStruct.appid = m.appId;//"1250000000";
preSignatureStruct.region = region;//"COS_REGION";
preSignatureStruct.bucket = bucket;//"examplebucket-1250000000";
preSignatureStruct.key = "exampleObject"; //object key
preSignatureStruct.httpMethod = "PUT"; //HTTP request method
preSignatureStruct.isHttps = true; //generate HTTPS request URL
preSignatureStruct.signDurationSecond = 600; //request signature time is 600s
preSignatureStruct.headers = null; //headers to validate in signature
preSignatureStruct.queryParameters = null; //request parameters to validate in URL signature
//Upload pre-signed URL (pre-signed URL calculated using permanent key)
Dictionary<string, string> queryParameters = new Dictionary<string, string>();
queryParameters.Add("x-cos-security-token",sessionToken);
Dictionary<string, string> headers = new Dictionary<string, string>();
string authorization = cosXml.GenerateSign(m.method,key,queryParameters,headers,expiredTime - startTime,expiredTime - startTime);

string host = "https://" + bucket + ".cos." + region + ".myqcloud.com";
Dictionary<string, object> response = new Dictionary<string, object>();
response.Add("cosHost",host);
response.Add("cosKey",key);
response.Add("authorization",authorization);
response.Add("securityToken",sessionToken);
Console.WriteLine($"{JsonConvert.SerializeObject(response)}");
}
}
}




Was this page helpful?
You can also Contact Sales or Submit a Ticket for help.
Yes
No

Feedback