阿里云OSS服务端签名后直传

阿里云OSS

第一步注册登录阿里云

第二步搜索对象存储oss并开通进入OSS管理控制台

第三步创建bucket仓库

第四步修改CORS(否则上传图片会有跨域问题)

第五步获取自己的AccessKey 会有accesskey id 和 accesskey secret

引入SDK

pom.xml

1
2
3
4
5
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>

如果使用的是Java 9及以上的版本,则需要添加jaxb相关依赖。添加jaxb相关依赖示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>

服务器端代码

https://help.aliyun.com/zh/oss/use-cases/obtain-signature-information-from-the-server-and-upload-data-to-oss?spm=a2c4g.11186623.0.0.47e21c75a88RI4

不使用spring boot starter

配置文件:

1
2
3
4
alibaba.cloud.oss.endpoint=
alibaba.cloud.access-key=
alibaba.cloud.secret-key=
aliyun.oss.file.bucketName=

在配置类或者启动类中添加:(只要spring 能创建并加入到容器中)

1
2
3
4
5
6
7
8
9
10
11
@Bean
public OSS ossClient(@Value("${alibaba.cloud.oss.endpoint}") String endpoint,
@Value("${alibaba.cloud.access-key}") String accessKeyId,
@Value("${alibaba.cloud.secret-key}") String accessKeySecret) {
CredentialsProvider credentialsProvider = null;
// 使用代码嵌入的RAM用户的访问密钥配置访问凭证。
credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);

OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
return ossClient;
}
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
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@RestController
public class OssController {

@Autowired
private OSS ossClient;

@Value("${alibaba.cloud.access-key}")
private String accessId;

@Value("${alibaba.cloud.oss.endpoint}")
private String endoint;

@Value("${aliyun.oss.file.bucketName}")
private String bucket;

@RequestMapping("oss/policy")
public Map<String, Object> Policy() {
// 填写Host地址,格式为https://bucketname.endpoint。
String host = "https://" + bucket + "." + endoint;
// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
String format = new SimpleDateFormat("yyyy:MM:hh").format(new Date());
String dir = format + "/";
Map<String, String> respMap = null;
try {
// 60秒过期
long expireTime = 6000;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);

PolicyConditions policyConds = new PolicyConditions();
// 内容大小范围
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 104857600);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);

respMap = new LinkedHashMap<String, String>();
respMap.put("accessid", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000));

} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
Map<String, Object> result = new HashMap<>();
result.put("data", respMap);
return result;
}

访问:http://localhost:8080/oss/policy 可以返回正确的值

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
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>OSS web直传</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
</head>
<body>

<ul>
<li>
<span>选择上传的文件:</span>
<input type="file" id="files"></li>
<li>
<button onclick="getOssSignature()">开始上传</button>
</li>
</ul>

</body>

<script typet="text/javascript" src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>


<!--OSS服务端签名后直传JS逻辑代码-->
<script>
//发送ajax获取服务端签名
function getOssSignature(){
var file = $('#files').get(0).files[0];//获取需要上传的文件对象
//检测文件是否存在
if(!file){
alert('请先选择文件');
return false;
}

//发送ajax请求我方php后端获取上传OSS时必要的参数信息
$.ajax({
type : "get", //提交方式
url : "./oss/policy",//路径
success : function(res) {//返回数据根据结果进行相应的处理

//上返回的参数使用formData中
let formData = new FormData();
formData.append('key', res.data.dir);
formData.append('OSSAccessKeyId', res.data.accessid);
formData.append('policy', res.data.policy);
formData.append('Signature', res.data.signature);
formData.append('callback', res.data.callback);
formData.append('success_action_status', 200); // 成功后返回的操作码
formData.append('file', file);
//接收到服务端返回的签名参数,开始通过另一个Ajax请求来上传文件到OSS
//成功获取签名后上传文件到阿里云OSS
$.ajax({
type : "POST", //提交方式
url : res.data.host,//路径
dataType:'XML',
processData: false,
cache: false,
async: false,
contentType: false,
//关键是要设置contentType 为false,不然发出的请求头 没有boundary
//该参数是让jQuery去判断contentType
data : formData,//要发送到OSS数据,使用我这个ajax的格式可避开跨域问题。
success : function(res2) {//返回数据根据结果进行相应的处理
console.log(res2);//返回success:ok 说明你就上传成功了
}
});
}
});
}
</script>


</html>

aliyun-spring-boot

阿里云维护开发了aliyun-spring-boot, 如果使用spring-boot可以更好的整合进来。

https://github.com/alibaba/aliyun-spring-boot

https://github.com/alibaba/aliyun-spring-boot/tree/master/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample


阿里云OSS服务端签名后直传
http://hanqichuan.com/2023/10/19/java/阿里云OSS服务端签名后直传/
作者
韩启川
发布于
2023年10月19日
许可协议