上传对象实践教程

最近更新时间:2024-07-24 10:10:01

我的收藏
本文档介绍如何搭建安全的临时密钥服务以及如何使用 Android SDK 初始化并上传。

方案优势

权限安全:可以有效限定安全的权限范围,只能用于上传指定的一个文件路径。
路径安全:由服务端决定随机的 COS 文件路径,可以有效避免已有文件被覆盖的问题和安全风险。

上传流程

1. 客户端选择文件,客户端将原始文件名发送给服务端。
2. 服务端根据文件名后缀,生成带时间的随机 COS 文件路径,并申请对应权限的临时密钥和 cos key 返回给客户端。
3. 客户端使用高级上传接口上传文件到 COS。

临时密钥搭建

临时密钥(临时访问凭证) 是通过 CAM 云 API 提供的接口,获取到权限受限的密钥。当需要发起 COS API 请求时,需要用到获取临时密钥接口返回信息中 的 TmpSecretId、TmpSecretKey 和 Token 三个字段,用于计算签名。
getKeyAndCredentials 接口会返回临时密钥信息和上传需要的 Bucket、 Region、 cosKey。
以下示例各语言示例代码:
NodeJS
Go
PHP
Python
Java
.Net
完整代码可参考 示例代码
// 临时密钥服务例子
const STS = require('qcloud-cos-sts');
const express = require('express');
const pathLib = require('path');
// 配置参数
const config = {
secretId: process.env.SecretId,
secretKey: process.env.SecretKey,
proxy: process.env.Proxy,
durationSeconds: 1800,
bucket: process.env.Bucket,
region: process.env.Region,
// 密钥的上传操作权限列表
allowActions: [
// 简单上传
'name/cos:PutObject',
// 分块上传
'name/cos:InitiateMultipartUpload',
'name/cos:ListMultipartUploads',
'name/cos:ListParts',
'name/cos:UploadPart',
'name/cos:CompleteMultipartUpload',
],
};

// 生成要上传的 COS 文件路径文件名
const generateCosKey = function (ext) {
const date = new Date();
const m = date.getMonth() + 1;
const ymd = `${date.getFullYear()}${m < 10 ? `0${m}` : m}${date.getDate()}`;
const r = ('000000' + Math.random() * 1000000).slice(-6);
const cosKey = `file/${ymd}/${ymd}_${r}${ext ? `${ext}` : ''}`;
return cosKey;
};
// 创建临时密钥服务
const app = express();
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
// 获取临时密钥
function getSts({ cosKey, condition }) {
return new Promise((resolve, reject) => {
// 获取临时密钥
const AppId = config.bucket.substr(config.bucket.lastIndexOf('-') + 1);
let resource =
'qcs::cos:' +
config.region +
':uid/' +
AppId +
':' +
config.bucket +
'/' +
cosKey;
console.log('检查resource是否正确', resource);
const policy = {
version: '2.0',
statement: [
{
action: config.allowActions,
effect: 'allow',
resource: [
// cos相关授权路径
resource,
// ci相关授权路径 按需使用
// 'qcs::ci:' + config.region + ':uid/' + AppId + ':bucket/' + config.bucket + '/' + 'job/*',
],
condition
},
],
};
const startTime = Math.round(Date.now() / 1000);
STS.getCredential(
{
secretId: config.secretId,
secretKey: config.secretKey,
proxy: config.proxy,
region: config.region,
durationSeconds: config.durationSeconds,
// endpoint: 'sts.internal.tencentcloudapi.com', // 支持设置sts内网域名
policy: policy,
},
function (err, tempKeys) {
if (tempKeys) tempKeys.startTime = startTime;
if (err) {
reject(err);
} else {
resolve(tempKeys);
}
}
);
});
}
// 返回临时密钥和上传信息,客户端自行计算签名
app.get('/getKeyAndCredentials', function (req, res, next) {
// 业务自行实现 用户登录态校验,比如对 token 校验
// const userToken = req.query.userToken;
// const canUpload = checkUserRole(userToken);
// if (!canUpload) {
// res.send({ error: '当前用户没有上传权限' });
// return;
// }

// 上传文件可控制类型、大小,按需开启
const permission = {
limitExt: false, // 限制上传文件后缀
extWhiteList: ['jpg', 'jpeg', 'png', 'gif', 'bmp'], // 限制的上传后缀
limitContentType: false, // 限制上传 contentType
limitContentLength: false, // 限制上传文件大小
};
// 客户端传进原始文件名,这里根据文件后缀生成随机 Key
const filename = req.query.filename;
const ext = pathLib.extname(filename);
const cosKey = generateCosKey(ext);
const condition = {};
// 1. 限制上传文件后缀
if (permission.limitExt) {
const extInvalid = !ext || !extWhiteList.includes(ext);
if (extInvalid) {
res.send({ error: '非法文件,禁止上传' });
}
}
// 2. 限制上传文件 content-type
if (permission.limitContentType) {
Object.assign(condition, {
'string_like': {
// 只允许上传 content-type 为图片类型
'cos:content-type': 'image/*'
}
});
}

// 3. 限制上传文件大小
if (permission.limitContentLength) {
Object.assign(condition, {
'numeric_less_than_equal': {
// 上传大小限制不能超过 5MB
'cos:content-length': 5 * 1024 * 1024
},
});
}

getSts({ cosKey, condition })
.then((data) => {
res.send({
TmpSecretId: data.credentials.tmpSecretId,
TmpSecretKey: data.credentials.tmpSecretKey,
SessionToken: data.credentials.sessionToken,
StartTime: Math.round(Date.now() / 1000),
ExpiredTime: data.expiredTime,
Bucket: config.bucket,
Region: config.region,
Key: cosKey,
});
})
.catch((err) => {
console.log('sts error', err);
res.send(err);
});
});

app.all('*', function (req, res, next) {
res.send({ code: -1, message: '404 Not Found' });
});
// 启动签名服务
app.listen(3000);
console.log('app is listening at http://127.0.0.1:3000');
完整代码可参考 示例代码
package main

import (
"fmt"
"github.com/tencentyun/qcloud-cos-sts-sdk/go"
"math/rand"
"os"
"time"
)

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: false,
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"), // 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考https://cloud.tencent.com/document/product/598/37140
SecretKey: os.Getenv("SECRETKEY"), // 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考https://cloud.tencent.com/document/product/598/37140
Proxy: os.Getenv("Proxy"),
DurationSeconds: 1800,
Bucket: "bucket-12500000000",
Region: "ap-guangzhou",
AllowActions: []string{
"name/cos:PutObject",
"name/cos:InitiateMultipartUpload",
"name/cos:ListMultipartUploads",
"name/cos:ListParts",
"name/cos:UploadPart",
"name/cos:CompleteMultipartUpload",
},
}
return config
}

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

func main() {

config := getConfig()

permission := getPermission()

c := sts.NewClient(
// 通过环境变量获取密钥, os.Getenv 方法表示获取环境变量
config.SecretId, //os.Getenv("SECRETID"), // 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考https://cloud.tencent.com/document/product/598/37140
config.SecretKey, //os.Getenv("SECRETKEY"), // 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考https://cloud.tencent.com/document/product/598/37140
nil,
// sts.Host("sts.internal.tencentcloudapi.com"), // 设置域名, 默认域名sts.tencentcloudapi.com
// sts.Scheme("http"), // 设置协议, 默认为https,公有云sts获取临时密钥不允许走http,特殊场景才需要设置http
)

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 {
fmt.Printf("%+v\\n", "非法文件,禁止上传")
return
}
}

if permission.LimitContentType {
condition["string_like"] = map[string]interface{}{
// 只允许上传 content-type 为图片类型
"cos:content-type": "image/*",
}
}

// 3. 限制上传文件大小
if permission.LimitContentLength {
condition["numeric_less_than_equal"] = map[string]interface{}{
// 上传大小限制不能超过 5MB
"cos:content-length": 5 * 1024 * 1024,
}
}
// 策略概述 https://cloud.tencent.com/document/product/436/18023
opt := &sts.CredentialOptions{
DurationSeconds: int64(config.DurationSeconds),
Region: config.Region,
Policy: &sts.CredentialPolicy{
Version: "2.0",
Statement: []sts.CredentialPolicyStatement{
{
// 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
Action: config.AllowActions,
Effect: "allow",
Resource: []string{
// 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
// 存储桶的命名格式为 BucketName-APPID,此处填写的 bucket 必须为此格式
"qcs::cos:ap-guangzhou:uid/" + config.appId + ":" + config.Bucket + "/" + generateCosKey(ext),
},
// 开始构建生效条件 condition
// 关于 condition 的详细设置规则和COS支持的condition类型可以参考https://cloud.tencent.com/document/product/436/71306
Condition: condition,
},
},
},
}

// 请求临时密钥
res, err := c.GetCredential(opt)
if err != nil {
panic(err)
}
fmt.Printf("%+v\\n", res)
fmt.Printf("%+v\\n", res.Credentials)
}
完整代码可参考 示例代码
<?php
require_once __DIR__ . '/vendor/autoload.php';

use QCloud\\COSSTS\\Sts;

// 生成要上传的 COS 文件路径文件名
function generateCosKey($ext) {
$ymd = date('Ymd');
$r = substr('000000' . rand(), -6);
$cosKey = 'file/' . $ymd. '/' . $ymd . '_' . $r;
if ($ext) {
$cosKey = $cosKey . '.' . $ext;
}
return $cosKey;
};

// 获取单一文件上传权限的临时密钥
function getKeyAndCredentials($filename) {
// 业务自行实现 用户登录态校验,比如对 token 校验
// $canUpload = checkUserRole($userToken);
// if (!$canUpload) {
// return '当前用户没有上传权限';
// }

// 上传文件可控制类型、大小,按需开启
$permission = array(
'limitExt' => false, // 限制上传文件后缀
'extWhiteList' => ['jpg', 'jpeg', 'png', 'gif', 'bmp'], // 限制的上传后缀
'limitContentType' => false, // 限制上传 contentType
'limitContentLength' => false, // 限制上传文件大小
);
$condition = array();

// 客户端传进原始文件名,这里根据文件后缀生成随机 Key
$ext = pathinfo($filename, PATHINFO_EXTENSION);

// 1. 限制上传文件后缀
if ($permission['limitExt']) {
if ($ext === '' || array_key_exists($ext, $permission['extWhiteList'])) {
return '非法文件,禁止上传';
}
}

// 2. 限制上传文件 content-type
if ($permission['limitContentType']) {
// 只允许上传 content-type 为图片类型
$condition['string_like'] = array('cos:content-type' => 'image/*');
}

// 3. 限制上传文件大小
if ($permission['limitContentLength']) {
// 上传大小限制不能超过 5MB
$condition['numeric_less_than_equal'] = array('cos:content-length' => 5 * 1024 * 1024);
}

$cosKey = generateCosKey($ext);
$bucket = 'test-131234567'; // 换成你的 bucket
$region = 'ap-guangzhou'; // 换成 bucket 所在园区
$config = array(
'url' => 'https://sts.tencentcloudapi.com/', // url和domain保持一致
'domain' => 'sts.tencentcloudapi.com', // 域名,非必须,默认为 sts.tencentcloudapi.com
'proxy' => '',
'secretId' => getenv('GROUP_SECRET_ID'), // 固定密钥,若为明文密钥,请直接以'xxx'形式填入,不要填写到getenv()函数中
'secretKey' => getenv('GROUP_SECRET_KEY'), // 固定密钥,若为明文密钥,请直接以'xxx'形式填入,不要填写到getenv()函数中
'bucket' => $bucket, // 换成你的 bucket
'region' => $region, // 换成 bucket 所在园区
'durationSeconds' => 1800, // 密钥有效期
'allowPrefix' => array($cosKey), // 只分配当前 key 的路径权限
// 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
'allowActions' => array (
// 简单上传
'name/cos:PutObject',
// 分片上传
'name/cos:InitiateMultipartUpload',
'name/cos:ListMultipartUploads',
'name/cos:ListParts',
'name/cos:UploadPart',
'name/cos:CompleteMultipartUpload'
),
);

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

$sts = new Sts();
$tempKeys = $sts->getTempKeys($config);
$resTemp = array(
'TmpSecretId' => $tempKeys['credentials']['tmpSecretId'],
'TmpSecretKey' => $tempKeys['credentials']['tmpSecretKey'],
'SessionToken' => $tempKeys['credentials']['sessionToken'],
'StartTime' => time(),
'ExpiredTime' => $tempKeys['expiredTime'],
'Bucket' => $bucket,
'Region' => $region,
'Key' => $cosKey,
);
echo json_encode($resTemp);
return $resTemp;
}
完整代码可参考 示例代码
#!/usr/bin/env python
# coding=utf-8
import json
import os
import datetime
import random

from sts.sts import Sts


if __name__ == '__main__':

# 配置参数
config = {
"filename":"test.jpg",
"appId": "125000000",
"secretId": os.getenv("SecretId"),
"secretKey": os.getenv("SecretKey"),
"proxy": os.getenv("Proxy"),
"durationSeconds": 1800,
"bucket": "bucket-125000000",
"region": "ap-guangzhou",
# 密钥的上传操作权限列表
"allowActions": [
# 简单上传
"name/cos:PutObject",
# 分块上传
"name/cos:InitiateMultipartUpload",
"name/cos:ListMultipartUploads",
"name/cos:ListParts",
"name/cos:UploadPart",
"name/cos:CompleteMultipartUpload",
],
}

permission = {
"limitExt": False, # 限制上传文件后缀
"extWhiteList": ["jpg", "jpeg", "png", "gif", "bmp"], # 限制的上传后缀
"limitContentType": False, # 限制上传 contentType
"limitContentLength": False, # 限制上传文件大小
}

# 生成要上传的 COS 文件路径文件名
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(separator)
ext = segments[-1] if segments else ""

resource = f"qcs::cos:{config['region']}:uid/{config['appId']}:{config['bucket']}/{generate_cos_key(ext)}"

condition = {}

# 1. 限制上传文件后缀
if permission["limitExt"]:
ext_invalid = not ext or ext not in permission["extWhiteList"]
if ext_invalid:
print('非法文件,禁止上传')

# 2. 限制上传文件 content-type
if permission["limitContentType"]:
condition.update({
"string_like": {
# 只允许上传 content-type 为图片类型
"cos:content-type": "image/*"
}
})

# 3. 限制上传文件大小
if permission["limitContentLength"]:
condition.update({
"numeric_less_than_equal": {
# 上传大小限制不能超过 5MB
"cos:content-length": 5 * 1024 * 1024
}
})

def get_credential_demo():
credentialOption = {
# 临时密钥有效时长,单位是秒
'duration_seconds': config.get('durationSeconds'),
'secret_id': config.get("secretId"),
# 固定密钥
'secret_key': config.get("secretKey"),
# 换成你的 bucket
'bucket': config.get("bucket"),
'proxy': config.get("proxy"),
# 换成 bucket 所在地区
'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()
print('get data : ' + json.dumps(dict(response), indent=4))
except Exception as e:
print(e)

get_credential_demo()
完整代码可参考 示例代码
package com.tencent.cloud;

import com.tencent.cloud.assumerole.AssumeRoleParam;
import com.tencent.cloud.cos.util.Jackson;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.*;

public class GetKeyAndCredentialsTest {

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;
}

// 获取配置信息
public TreeMap<String,Object> getConfig(){

String bucket = "bucket-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] : "";

// 临时密钥限制
Boolean limitExt = false; // 限制上传文件后缀
List extWhiteList = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp"); // 限制的上传后缀
Boolean limitContentType = false; // 限制上传 contentType
Boolean limitContentLength = false; // 限制上传文件大小


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

// 1. 限制上传文件后缀
if (limitExt) {
boolean extInvalid = ext == null || !extWhiteList.contains(ext);
if (extInvalid) {
System.out.println("非法文件,禁止上传");
return null;
}
}

// 2. 限制上传文件 content-type
if (limitContentType) {
condition.put("string_like", new HashMap<String, String>() {{
put("cos:content-type", "image/*");
}});
}

// 3. 限制上传文件大小
if (limitContentLength) {
condition.put("numeric_less_than_equal", new HashMap<String, Long>() {{
put("cos:content-length", 5L * 1024 * 1024);
}});
}

String resource = "qcs::cos:" + region + ":uid/" + appId + ':' + bucket + '/' + generateCosKey(ext);
List allowActions = Arrays.asList(
// 简单上传
"name/cos:PutObject",
// 分块上传
"name/cos:InitiateMultipartUpload",
"name/cos:ListMultipartUploads",
"name/cos:ListParts",
"name/cos:UploadPart",
"name/cos:CompleteMultipartUpload"
);


// 构建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));


// 构建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("policy",Jackson.toJsonPrettyString(policy));
return config;
}

/**
* 基本的临时密钥申请示例,适合对一个桶内的一批对象路径,统一授予一批操作权限
*/
@Test
public void testGetKeyAndCredentials() {
TreeMap config = this.getConfig();

try {
Response response = CosStsClient.getCredential(config);
System.out.println(response.credentials.tmpSecretId);
System.out.println(response.credentials.tmpSecretKey);
System.out.println(response.credentials.sessionToken);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("no valid secret !");
}
}

}
完整代码可参考 示例代码
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 Newtonsoft.Json;
using Formatting = System.Xml.Formatting;


namespace COSSnippet
{
public class GetKeyAndCredentials
{
//永久密钥
string secretId = "";
string secretKey = "";

string bucket = "bucket-125000000";
string appId = "125000000";
string region = "ap-guangzhou";
string filename = "test.jpg";
int time = 1800;
// 限制
Boolean limitExt = false; // 限制上传文件后缀
List<string> extWhiteList = new List<String> { "jpg", "jpeg", "png", "gif", "bmp" }; // 限制的上传后缀
Boolean limitContentType = false; // 限制上传 contentType
Boolean limitContentLength = false; // 限制上传文件大小

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"); // 生成6位随机数,前面补零
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[] { // 允许的操作范围,这里以上传操作为例
"name/cos:PutObject",
"name/cos:PostObject",
"name/cos:InitiateMultipartUpload",
"name/cos:ListMultipartUploads",
"name/cos:ListParts",
"name/cos:UploadPart",
"name/cos:CompleteMultipartUpload",
};
string[] segments = filename.Split("."); string ext = segments.Length > 0 ? segments[segments.Length - 1] : string.Empty;
string resource = $"qcs::cos:{region}:uid/{appId}:{bucket}/{generateCosKey(ext)}";
var condition = new Dictionary<string, object>();
// 1. 限制上传文件后缀
if (limitExt)
{
var extInvalid = string.IsNullOrEmpty(ext) || !extWhiteList.Contains(ext);
if (extInvalid)
{
Console.WriteLine("非法文件,禁止上传");
return null;
}
}

// 2. 限制上传文件 content-type
if (limitContentType)
{
condition["string_like"] = new Dictionary<string, string>
{
{ "cos:content-type", "image/*" } // 只允许上传 content-type 为图片类型
};
}

// 3. 限制上传文件大小
if (limitContentLength)
{
condition["numeric_less_than_equal"] = new Dictionary<string, long>
{
{ "cos:content-length", 5 * 1024 * 1024 } // 上传大小限制不能超过 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 }
}
}
}
};

// 序列化为 JSON 并输出
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("policy", jsonPolicy);
return config;
}
// 获取联合身份临时访问凭证 https://cloud.tencent.com/document/product/1312/48195
public Dictionary<string, object> GetCredential()
{

var config = getConfig();
//获取临时密钥
Dictionary<string, object> credential = STSClient.genCredential(config);
return credential;
}
static void Main(string[] args)
{
GetKeyAndCredentials m = new GetKeyAndCredentials();
Dictionary<string, object> result = m.GetCredential();
Console.WriteLine("Credentials:" + result["Credentials"]);
Console.WriteLine("ExpiredTime:" + result["ExpiredTime"]);
Console.WriteLine("StartTime:" + result["StartTime"]);
}
}
}

客户端发起上传

// 假设需要上传的文件本地路径为filePath
String filePath = "/path/to/your/file.txt";

// 1、从服务端请求上传和签名信息
File file = new File(filePath);
// getKeyAndCredentials方法见下一个代码块
JSONObject keyAndCredentials = getKeyAndCredentials(file.getName());
String region = keyAndCredentials.getString("Region");
String bucket = keyAndCredentials.getString("Bucket");
String cosKey = keyAndCredentials.getString("Key");
String tmpSecretId = keyAndCredentials.getString("TmpSecretId");
String tmpSecretKey = keyAndCredentials.getString("TmpSecretKey");
String sessionToken = keyAndCredentials.getString("SessionToken");
long startTime = keyAndCredentials.getLong("StartTime");
long expiredTime = keyAndCredentials.getLong("ExpiredTime");

// 2、初始化 COS SDK: CosXmlService和TransferManager
// 创建 CosXmlServiceConfig 对象,根据需要修改默认的配置参数
CosXmlServiceConfig serviceConfig = new CosXmlServiceConfig.Builder()
.setRegion(region)
.isHttps(true) // 使用 HTTPS 请求, 默认为 HTTP 请求
.builder();
// 初始化一个 CosXmlService 的实例,可以不设置临时密钥回调
CosXmlService cosXmlService = new CosXmlService(context, serviceConfig);
// 初始化 TransferConfig,这里使用默认配置,如果需要定制,请参考 SDK 接口文档
TransferConfig transferConfig = new TransferConfig.Builder().build();
// 初始化 TransferManager
TransferManager transferManager = new TransferManager(cosXmlService, transferConfig);

// 3、进行上传
PutObjectRequest putRequest = new PutObjectRequest(bucket, cosKey, filePath);
SessionQCloudCredentials sessionQCloudCredentials = new SessionQCloudCredentials(tmpSecretId, tmpSecretKey,
sessionToken, startTime, expiredTime);
putRequest.setCredential(sessionQCloudCredentials);
COSXMLUploadTask uploadTask = transferManager.upload(putRequest, null);
//设置上传进度回调
uploadTask.setCosXmlProgressListener(new CosXmlProgressListener() {
@Override
public void onProgress(long complete, long target) {
// todo Do something to update progress...
}
});
//设置返回结果回调
uploadTask.setCosXmlResultListener(new CosXmlResultListener() {
@Override
public void onSuccess(CosXmlRequest request, CosXmlResult result) {
COSXMLUploadTask.COSXMLUploadTaskResult uploadResult =
(COSXMLUploadTask.COSXMLUploadTaskResult) result;
}

// 如果您使用 kotlin 语言来调用,请注意回调方法中的异常是可空的,否则不会回调 onFail 方法,即:
// clientException 的类型为 CosXmlClientException?,serviceException 的类型为 CosXmlServiceException?
@Override
public void onFail(CosXmlRequest request,
@Nullable CosXmlClientException clientException,
@Nullable CosXmlServiceException serviceException) {
if (clientException != null) {
clientException.printStackTrace();
} else {
serviceException.printStackTrace();
}
}
});
从服务端请求上传和签名信息。
/**
* 获取上传和签名信息
*
* @param filename 文件名
* @return 上传和签名信息
*/
private JSONObject getKeyAndCredentials(String filename) {
// 获取上传和签名信息
HttpURLConnection getConnection = null;
try {
//上面搭建的临时密钥服务(正式环境 请替换成正式的业务url)
URL url = new URL("http://127.0.0.1:3000/getKeyAndCredentials?filename=" + filename);
getConnection = (HttpURLConnection) url.openConnection();
getConnection.setRequestMethod("GET");

int responseCode = getConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(getConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
reader.close();
JSONObject jsonObject;
try {
// 服务端接口需要返回:上传的存储桶、地域、随机路径的对象键、临时密钥
jsonObject = new JSONObject(stringBuilder.toString());
return jsonObject;
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("getKeyAndCredentials", "getKeyAndCredentials HTTP error code: " + responseCode);
}
} catch (IOException e) {
e.printStackTrace();
Log.e("getKeyAndCredentials", "getKeyAndCredentials Error sending GET request: " + e.getMessage());
} finally {
if (getConnection != null) {
getConnection.disconnect();
}
}
return null;
}

相关文档