# 对象存储

针对各个公有云和私有云提供功能不同,为了使上层开发与具体应用解耦,所以提供SDK适配各个云厂商,供上层服务调用。可以通过简单的切换配置文件,达到切换不同厂商的功能。

# 功能介绍

ObjectStorage 是为了适配多云的对象存储而开发的 SDK,用于支持产品在多个云的环境部署运行。产品可以通过简单的修改配置,不用修改代码就能完成在多云之间的平滑部署迁移。

  • 适配了阿里云的 OSS,华为云的 OBS ,腾讯云的COS,以及私有化环境下的 minioceph以及青云。
  • 支持对象存储的各种操作:上传文件,下载文件,签名直传,缩略图,视频截帧等。
  • 支持通过临时授权STS的方式获取临时密钥,进行对象存储的访问。

基于ObjectStorage提供的便捷,为了在使用上可以更加方便,我们提供了object-storage-spring-boot-starter,其内部是基于ObjectStorage的实现,为上层提供了自动配置的功能,也就是starter包。

# 使用流程

# 1.配置settings.xml私仓地址

<!-- scg maven仓库 -->
<repository>
    <id>scg-private</id>
    <name>maven-scg-private</name>
    <url>http://packages.glodon.com/artifactory/maven-scg-private/</url>
</repository>
1
2
3
4
5
6

# 2.项目中添加 pom 依赖

<dependency>
    <groupId>com.glodon.cloud</groupId>
    <artifactId>object-storage-spring-boot-starter</artifactId>
     <version>1.0.4</version>
</dependency>
1
2
3
4
5

如果结合spring-cloud-glodon使用,则通过引入spring-cloud-glodon-dependencies后管理依赖版本即可

<dependency>
    <groupId>com.glodon.cloud</groupId>
    <artifactId>object-storage-spring-boot-starter</artifactId>
</dependency>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.glodon.cloud</groupId>
            <artifactId>spring-cloud-glodon-dependencies</artifactId>
            <version>2.3.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3.配置yaml

object-storage:
	protocol: S3_HW #可选项 OSS、S3_HW、S3_COS、S3_AWS、S3_AWS_V4、S3_MINIO、S3_CEPH、S3_QY、S3
    endPoint: your.end-point
    accessKeyId: your.access.key.id
    accessKeySecret: your.access.key.secret
    # 新增可选配置项
    region: your-region
    pathStyleAccess: true/false # 是否强制开启路径形式的资源访问
    externalEndpoint: your-external-endpoint # 是否使用对外的endpoint,默认false。在对象存储的某些操作中,例如获得签名URL时,需要给用户对外的endpoint
    maxConnections: # 连接数
    connectionTimeout: # 连接超时时间
    socketTimeout: # socket超时时间
    # 废弃配置项: 老版本的图片处理和视频处理等功能需要配置云厂商,当前新版本无需配置即可使用
    provider: ali/huawei
1
2
3
4
5
6
7
8
9
10
11
12
13
14

配置项说明:

/**
     * 是否强制开启路径形式的资源访问
     *
     * (指定为Boolean.TRUE,那么使用endpoint/bucket的方式来访问)
     * (指定为Boolean.FALSE,那么使用bucket.endpoint的方式来访问)
     * (不指定则为null,使用OSS或者S3的默认方式:
     *      OSS默认采用bucket.endpoint;
     *      S3默认对于ip格式的endpoint和非合法DNS格式的bucket采用endpoint/bucket,
     *          而其他情况使用bucket.endpoint;
     *      S3_HW:与S3默认情况相同;
     *      S3_QY:与S3默认情况相同;
     *      S3_CEPH:默认使用endpoint/bucket方式访问
     *      S3_MINIO: 默认使用endpoint/bucket方式访问;
     *      )
     *
     *  默认值大多数情况下足够使用,绝大多数情况不需要指定这个参数
     */
private Boolean pathStyleAccess;



/**
	* 该配置项当前主要针对,签名直传功能的接口,可以通过externalEndpoint控制获取到的host是内网还是外网
	*/
private String externalEndpoint;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 4.注入对象

配置完成后,就可以在代码中注入ObjectClient来使用。

@Autowired
ObjectClient objectClient;
1
2

# 5.常用操作

# 5.1 文件上传下载

// 上传文件
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
objectClient.put(objectBasicInfo, file);

// 下载文件
ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
objectClient.get(objectBasicInfo, file);

1
2
3
4
5
6
7
8

# 5.2 获取签名URL

ObjectBasicInfo objectBasicInfo = new ObjectBasicInfo(bucketName, fileName);
String strUrl = objectClient.getSignedURL(objectBasicInfo, 600, "", SignedUrlBehavior.DOWNLOAD, null).toString();// 过期时间设置成600s
1
2

# 5.3 图片操作

// 1.先定义 DataProcessor
DataProcessor processor = new DataProcessor(DataProcessor.Type.IMAGE, Collections.singletonList("resize,w_100,h_100"));
// 2.调用下面两个方法之一
ObjectClient.getSignedURL(ObjectBasicInfo objectBasicInfo, int expiredTime, String fileName,SignedUrlBehavior behavior, DataProcessor processor);
RawClient.getSignedURL(SignedURLRequest signedURLRequest);
1
2
3
4
5

针对华为云和阿里OSS,图片处理是全功能支持的。

针对ceph、minIO、QingYunS3,图片处理功能是在object-storage中自己实现的。实现方式是基于github上的开源项目thumbnailator:前往GitHub查看

仅支持了resize 操作,format操作。resize 功能与阿里云保持一致,但是调用resize,允许放大和缩小(没有实现limit_0和limit_1功能)。

在一个action中,参数优先级[w,h]>l>s>p,高优先级的参数将覆盖低优先级的参数操作,与出现的顺序无关,同一个参数出现多次,后面的会覆盖前面的,参数m没有优先级。

原理:先将图片下载下来,然后使用工具处理之后,将处理后的图片上传至同一个bucket下的ImageProcessTempFolder文件夹内。文件名字为:etag+actions+format

# 5.4 视频截帧

// 1.定义 processor
DataProcessor processor = new DataProcessor(DataProcessor.Type.VIDEO,
                Collections.singletonList("snapshot,t_5000,f_jpg,w_800,h_600,m_fast"));
// 2.调用下面两个方法之一获取截图
ObjectClient.getSignedURL(ObjectBasicInfo objectBasicInfo, int expiredTime, String fileName,SignedUrlBehavior behavior, DataProcessor processor));

RawClient.getSignedURL(SignedURLRequest signedURLRequest);
1
2
3
4
5
6
7
参数 描述 取值范围
t 截图时间 单位ms,[0,视频时长]
w 截图宽度,如果指定为0则按照比例自动计算 像素值:[0,视频宽度]
h 截图高度,如果指定为0则按照比例自动计算,如果w和h都为0则输出为原视频宽高 像素值:[0,视频高度]
m 截图模式,不指定则为默认模式,根据时间精确截图,如果指定为fast则截取该时间点之前的最近的一个关键帧 枚举值:fast
f 输出图片格式 枚举值:jpg、png

# 5.5 签名直传

PostPolicyRequest postPolicyRequest = new PostPolicyRequest(600, 1000L, "your-bucket");
PostPolicyInfo postPolicyInfo = objectClient.generatePostPolicy(postPolicyRequest);
1
2

拿到 postPolicyInfo 后,浏览器发起的请求应该如下

 curl -X POST ${info.host} \
  -H 'content-type: multipart/form-data' \
  -F 'key=ABCD.file' \
  -F policy=${info.encodedPolicy} \
  -F ${info.accessIdName}=${info.accessId} \
  -F callback=${info.callback} \
  -F signature=${info.postSignature} \
  -F success_action_status=200 \
  -F 'file=@/your/path/ABCD.file' 
1
2
3
4
5
6
7
8
9
# 5.5.1 示例

服务端需要提供获取签名信息的接口(本示例以java为例)

@RestController
@CrossOrigin(allowCredentials = "true")
public class ObjectStorageController {

    @Autowired
    private ObjectClient objectClient;

    @GetMapping("signature")
    public String getSignature(){
        PostPolicyRequest postPolicyRequest = new PostPolicyRequest(600, 10 * 1024 * 1024L, bucketName);
        PostPolicyInfo postPolicyInfo = objectClient.generatePostPolicy(postPolicyRequest);
        return JSONObject.toJSONString(postPolicyInfo);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

前端html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>OBS web直传</title>
</head>

<body>
<h2 align="center">web直传</h2>
<div>
    <p align="center">
        <input type="file" id="post_file" name="post_file">
    </p>
    <p align="center">
        <button type="submit" value="上传" class="btn btn-success" onclick="postFile()">上传</button>
    </p>
</div>
</body>

<script type="text/javascript">
    function postFile() {
        // 获取签名的服务端地址
        const signUrl = "http://localhost:9000/signature";
        // 1.获取文件
        const resultFile = document.getElementById("post_file").files[0];
        // 2.获取签名 result, 结构如下
        /**
         {
          "accessId": "XXXXXXX",
          "accessIdName": "OSSAccessKeyId",
          "contentDisposition": "inline/attachment",
          "contentType": "application/octet-stream",
          "encodedPolicy": "XXXXXX",
          "expireTimeSeconds": 1603784561,
          "host": "XXXXXX",
          "postPolicy": "{expiration:xxxxxx,conditions:[[content-length-range,0,10485760],{bucket:xxxxxx},{success_action_status:200},{Content-Disposition:xxxxxx},{Content-Type:xxxxxx},[starts-with,$key,xxxxxx]]}",
          "postSignature": "xxxxxxx"
        }
         */
        const result = getSignature(signUrl);
        // 3.解析从服务端获取到的签名和策略相关的信息
        const policy = resolvePostPolicy(result.postPolicy);
        // 4.上传 (注意设置 isS3 参数)
        let uploadResult = postObjectByAjax(resultFile, result.accessId, result.encodedPolicy,
            result.postSignature, result.host, policy.contentType, policy.contentDisposition, policy.keyPrefix, false);
        if (uploadResult === true) {
            alert("上传成功")
        } else {
            alert("上传失败")
        }
    }
</script>
<script src="https://yzl-oss-test.oss-cn-beijing.aliyuncs.com/objectstorage-web/objectstorage.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

注意

上述html中https://yzl-oss-test.oss-cn-beijing.aliyuncs.com/objectstorage-web/objectstorage.js是云中立提供的objectstorage.js下载地址,可以直接引用;若需要修改,也可以从下方示例下载链接中下载后修改使用。

objectstorage.js文件

/**
 * @Author: baijd-a
 * @Date: 2020-10-26 15:58:29
 * @LastEditTime: 2020-10-26 15:58:29
 * @LastEditors: baijd-a
 * @Description: 采用云中立平台的对象存储适配,下面代码演示了前端如何采用签名直传的方式上传文件到 OSS、S3
 * 针对请求方式可采用 ajax axios
 */

/**
 * 根据url从服务端获取签名直传的签名相关信息
 * @param url
 * @returns 签名相关信息
 */
function getSignature(url) {
    let result = null;
    $.ajax({
        url: url,
        type: "get",
        async: false,
        success: function (data) {
            result = JSON.parse(data);
        }
    });
    return result;
}

/**
 * 通过 Ajax 上传文件到云服务
 *
 * 注意:
 *      请求时 FormData 参数中的 Content-Type, Content-Disposition, keyPrefix 需要和后端返回的策略中保持一致
 *
 * @param file 文件
 * @param accessId AK
 * @param policy 上传策略 base64值
 * @param signature 签名
 * @param host 上传的host
 * @param contentType 上传的Content-Type ===> 从服务端获取到的 Policy 中的值
 * @param contentDisposition 展示形式:内联(inline),附件下载(attachment; filename="xxx") ===> 从服务端获取到的 Policy 中的值
 * @param objectKeyPrefix 上传的key前缀
 * @param isS3 是否是S3服务[华为云、腾讯云、MINIO、CEPH、AWS]
 */
function postObjectByAjax(file, accessId, policy, signature, host, contentType, contentDisposition, objectKeyPrefix, isS3) {
    let form = new FormData();
    if (isS3) {
        form.append('AWSAccessKeyId', accessId); // S3 的 accessID; 若是上传到 S3 采用这个参数
    } else {
        form.append('OSSAccessKeyId', accessId);  // OSS 的 accessID; 若是上传到 OSS 采用这个参数
    }
    form.append('policy', policy);
    form.append('signature', signature);
    if (contentType !== null && contentType !== '') {
        form.append("Content-Type", contentType);
    }
    if (contentDisposition !== null && contentDisposition !== '') {
        form.append("Content-Disposition", contentDisposition)
    }
    if (objectKeyPrefix == null) {
        objectKeyPrefix = '';
    } else if (objectKeyPrefix !== '' && !objectKeyPrefix.endsWith("/")) {
        objectKeyPrefix += "/";
    }
    form.append('key', objectKeyPrefix + file.name);  // key: 文件上传的完整路径 若有目录含有目录
    form.append('success_action_status', 200); // 文件上传成功后返回的状态
    form.append('file', file);

    return _ajaxPostObject(host, form);
}

function _ajaxPostObject(url, formData) {
    var result = false;
    $.ajax({
        type: "POST",
        url: url,
        data: formData,
        processData: false,
        cache: false, // 设置为false将不会从浏览器缓存中加载请求信息
        async: false, // 发送同步请求
        contentType: false, // 避免服务器不能正常解析文件
        // dataType: 'JSONP', // jsonp只能提供get请求; 不涉及跨域, 写json即可
        success: function (data) {
            result = true;
        }
    });
    return result;
}

/**
 * 通过 Axios 上传文件到云服务
 *
 * 注意:
 *      请求时 FormData 参数中的 Content-Type, Content-Disposition, keyPrefix需要和后端返回的策略中保持一致
 *
 * @param file 文件
 * @param accessId AK
 * @param policy 上传策略 base64值
 * @param signature 签名
 * @param host 上传的host
 * @param contentType 上传的Content-Type  ===> 从服务端获取到的 Policy 中的值
 * @param contentDisposition 展示形式:内联(inline),附件下载(attachment; filename="xxx") ===> 从服务端获取到的 Policy 中的值
 * @param objectKeyPrefix 上传的key前缀
 * @param isS3 是否是S3服务[华为云、腾讯云、MINIO、CEPH、AWS]
 */
function postObjectByAxios(file, accessId, policy, signature, host, contentType, contentDisposition, objectKeyPrefix, isS3) {
    let form = new FormData();
    if (isS3) {
        form.append('AWSAccessKeyId', accessId); // S3 的 accessID; 若是上传到 S3 采用这个参数
    } else {
        form.append('OSSAccessKeyId', accessId);  // OSS 的 accessID; 若是上传到OSS 采用这个参数
    }
    form.append('policy', policy);
    form.append('signature', signature);
    form.append('signature', signature);
    if (contentType !== null && contentType !== '') {
        form.append("Content-Type", contentType);
    }
    if (contentDisposition !== null && contentDisposition !== '') {
        form.append("Content-Disposition", contentDisposition)
    }
    if (objectKeyPrefix == null) {
        objectKeyPrefix = '';
    } else if (objectKeyPrefix !== '' && !objectKeyPrefix.endsWith("/")) {
        objectKeyPrefix += "/";
    }
    form.append('key', objectKeyPrefix + file.name);  // key: 文件上传的完整路径 若有目录含有目录
    form.append('success_action_status', 200); // 文件上传成功后返回的状态,默认204
    form.append('file', file);  // 文件流

    let config = {
        header: {
            'Content-Type': 'multipart/form-data;',
        }
    };
    axios.post(host, form, config)
        .then(res => {
            console.log('上传成功');
        })
        .catch(error => {
            console.log('上传失败');
            console.log(error)
        });
}

/**
 * 判断对象是否为数组
 * @param o 要判断的对象
 * @returns {boolean} 判断结果
 */
function isArray(o) {
    return Object.prototype.toString.call(o) === '[object Array]';
}

/**
 * 将后端返回的结构中的策略 Policy json 进行解析
 * @param postPolicyJson Policy json
 * @returns {{contentDisposition: string, contentType: string, keyPrefix: string}}
 */
function resolvePostPolicy(postPolicyJson) {
    // 解析从服务端获取到的签名和策略相关的信息
    let contentDisposition = '';
    let contentType = '';
    let keyPrefix = '';

    const postPolicy = JSON.parse(postPolicyJson);
    const conditions = postPolicy.conditions;
    for (let i = 0; i < conditions.length; i++) {
        const condition = conditions[i];
        if (isArray(condition) && condition[0] === 'starts-with') {
            keyPrefix = condition[2];
        } else {
            if (condition['Content-Type'] !== undefined) {
                contentType = condition['Content-Type'];
            }
            if (condition['Content-Disposition'] !== undefined) {
                contentDisposition = condition['Content-Disposition'];
            }
        }
    }
    return {
        contentType: contentType,
        contentDisposition: contentDisposition,
        keyPrefix: keyPrefix
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

服务端http://localhost:9000/signature返回结果:

{
    "accessId": "xxxxx",
    "accessIdName": "OSSAccessKeyId",
    "encodedPolicy": "xxxxxxx",
    "expireTimeSeconds": 1603790181,
    "host": "https://xxxxxx.com",
    "postPolicy": "{expiration:xxxxxx,conditions:[[content-length-range,0,10485760],{bucket:xxxxxx},{success_action_status:200},{Content-Disposition:xxxxxx},{Content-Type:xxxxxx},[starts-with,$key,xxxxxx]]}",
    "postSignature": "xxxxxx"
}
1
2
3
4
5
6
7
8
9

阿里云上传结果:

General
    Request URL: https://xxxxxx.com/
    Request Method: POST
    Status Code: 200 OK
    Remote Address: xxx.xxx.xxx.xxx
    Referrer Policy: strict-origin-when-cross-origin


Form Data
    OSSAccessKeyId: xxxxxx
    policy: xxxxxx
    key: test1/xxxxxx.txt
    success_action_status: 200
    file: (binary)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 5.5.2 示例下载链接

示例下载链接

# 5.6 sts临时授权访问对象存储

STS(Security Token Service),可以进行临时授权访问。通过STS,您可以为第三方应用或子用户(即用户身份由您自己管理的用户)颁发一个自定义时效和权限的访问凭证。

阿里云 STS

华为云 STS

腾讯云 STS

亚马逊 STS

注意:由于临时授权访问密钥需要使用子用户的AK,SK进行API调用,所以如果没有子用户,请自建子用户,且分配S3操作权限。参考官网

MINIO STS

环境搭建步骤:根据minio光网介绍,我们可以通过AssumeRole方式获取临时访问密钥,其余实现方式参考Minio官网

注意:由于为临时授权访问密钥,所以此处需要使用子用户的AK,SK进行API使用,如果没有,请自建子用户。

# 5.6.1 阿里云示例

yaml配置

object-storage:
  end-point: https://your-region.aliyuncs.com
sts:
  protocol: OSS
  # sts-endpoint: # 阿里云有默认的stsEndpoint,也可以自己指定
  accessKeyId: xxxxxx
  accessKeySecret: xxxxxx
  roleArn: acs:ram::xxxxxx:role/xxxxxx # roleArn配置,STS获取临时授权需要用到
1
2
3
4
5
6
7
8

上述配置肿的sts,已经配置了一个sts的客户端stsClient,我们可以直接注入即可

@Autowired
private StsClient stsClient;
1
2

然后我们需要根据stsClient获取临时密钥,用临时密钥构造一个对象存储的客户端注入spring容器使用

此处以阿里云为例,指定特定bucket下的resource权限*

@Bean
public ObjectClient objectClient() {
    final String[] actions = {"oss:*"};
    final String[] resources = {"acs:oss:*:*:" + your-bucketName, "acs:oss:*:*:" + your-bucketName + "/*"};
	// 根据上述指定的 actions和 resources,构造请求策略
    StsRequestPolicyStatement statement = new StsRequestPolicyStatement.Builder()
        .action(actions)
        .resource(resources)
        .build();
    StsRequestPolicy stsRequestPolicy = new StsRequestPolicy.Builder()
        .statement(new StsRequestPolicyStatement[]{statement})
        .build();
    // 根据构造的请求策略和临时密钥有效时常,获取临时密钥
    StsResponse stsResponse = stsClient.getStsResponse(stsRequestPolicy, 15 * 60);
    System.out.println(stsResponse.toString());
	// 根据获取的临时密钥构造ObjectClient的配置
    RawClientConfig.Builder configBuilder = RawClientConfig.builder()
        .endpoint(endpoint)
        .accessKeyId(stsResponse.getAccessKeyId())
        .secretAccessKey(stsResponse.getAccessKeySecret())
        .securityToken(stsResponse.getSecurityToken());
    if (StringUtils.isNotBlank(region)) {
        configBuilder.region(region);
    }
	// 根据配置构造ObjectClient,注入spring容器
    return new ObjectClient(configBuilder.build(), ClientType.valueOf(protocol.toUpperCase()),
                            null, null);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

这样,就可以在您的应用中使用上述的ObjectClient

@Autowired
private ObjectClient objectClient;
1
2

注意:

由于临时密钥有有效时常限制,所以请注意临时密钥的过期。我们预留了接口供您在过期前更新临时密钥

// 获取新的临时密钥
StsResponse stsResponse = stsClient.getStsResponse(......);
// 更新临时密钥
objectClient.updateTempKeyAndSecret(stsResponse.getAccessKey(), stsResponse.getAccessSecret(), stsResponse.getSecurityToken());
1
2
3
4
# 5.6.2 S3相关示例

注意,目前S3相关的云对象存储中,支持STS的只有:华为云、腾讯云、亚马逊、MINIO云;所以如果要使用对象存储的STS功能,请在指定客户端类别时指定以上类型。

华为云:

yaml配置

object-storage:
  end-point: http://obs.your-region.myhuaweicloud.com
sts:
  protocol: S3_HW
  # sts-endpoint: # 华为云云有默认的stsEndpoint,也可以自己指定
  accessKeyId: xxxxxx
  accessKeySecret: xxxxxx
  ima-domain-name: your-domain-name
  ima-user-name: your-ima-user-name
  ima-password: your-ima-user-password
1
2
3
4
5
6
7
8
9
10

API调用:参见阿里云

腾讯云:

yaml配置

object-storage:
  end-point: cos.your-region.myqcloud.com
sts:  
  access-key-id: xxxxxx
  access-key-secret: xxxxxx
  protocol: S3_COS
  # 腾讯云STS获取临时授权时需要配置region和一个bucket
  bucket: your-bucket
  region: your-region
1
2
3
4
5
6
7
8
9

API调用:参见阿里云

AWS、AWS_V4:

yaml配置

object-storage:
  end-point: https://s3.your-region.amazonaws.com
  region: your-region
sts:  
  access-key-id: xxxxxx
  access-key-secret: xxxxxx
  protocol: S3_AWS/S3_AWS_V4
  region: your-region
  role-arn: arn:aws:iam::your:role/name
  external-id: Required # 可选
1
2
3
4
5
6
7
8
9
10

API调用:参见阿里云

MINIO:

yaml配置

object-storage:
  end-point: http://your-minio-host:port
sts:
  stsEndpoint: your-sts-endpoint
  access-key-id: xxxxxx # 字用户id
  access-key-secret: xxxxxx # 字用户secret
  protocol: S3_MINIO
1
2
3
4
5
6
7

API调用:参见阿里云

# 5.6.3 注意事项

1.上述示例中指定的各个action,resource请以各个云平台官网为准,如果您需要指定您的action、resource,请参考各个平台对应的官方文档介绍。

2.各个平台对应的指定生成临时秘钥的最短和最长有效时长有差异,请以各个平台官方文档为准,上述示例仅为参考。

3.由于各个平台需要的配置各有差异,所以当您切换平台时,请注意在yaml配置文件中修改相应的配置进行使用。

阿里云:需要配置角色的ARN -> roleArn

华为云:需要配置IAM用户所属账号信息、IAM用户名、IAM用户的登录密码 -> imaDomainName,imaUserName,imaPassword

腾讯云:腾讯云对象存储 获取临时密钥时需要且只能指定一个bucket,且需要指定region -> bucket,region

亚马逊:AWS对象存储需要指定配置角色的ARN和ExternalId(创建用户/角色时指定的)-> roleArn,externalId

MINIO云:需要配置stsEndpoint

4.由于各平台返回的临时秘钥中有效时间格式不同,所以本SDK统一使用阿里云的时间格式:2020-12-02T03:15:56Z,返回GMT时间。

# 5.6.4 常见错误

1.腾讯云 InvalidParameter.ResouceError

使用腾讯云出现如下错误

{"Response":{"Error":{"Code":"InvalidParameter.ResouceError","Message":"[QC_STS] resource error"},"RequestId":"xxxxxxxx"}}
1
2
3

解决方案:

由于腾讯云内部实现中使用了org.json包,所以确保您的应用中存在该包,且没有与其余包(例如:android-json)混淆,出现错误调用。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <artifactId>android-json</artifactId>
            <groupId>com.vaadin.external.google</groupId>
        </exclusion>
    </exclusions>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
  • 在线客服

  • 意见反馈