基于Post Policy的使用规则在服务端通过java后端代码完成签名,然后通过表单直传数据到OSS。由于服务端签名直传无需将AccessKey暴露在前端页面,相比JavaScript客户端签名直传具有更高的安全性。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
@GetMapping("/policy")
public R policy() {
LinkedHashMap<String, String> map = ossService.policy();
return R.ok().put("data",map);
}
@Autowired
OSS ossClient;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
public LinkedHashMap<String, String> policy() {
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
// 填写Host地址,格式为https://bucketname.endpoint。
String host = "https://" + bucket + "." + endpoint;
// 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
// String callbackUrl = "https://192.168.0.0:8888";
// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
String dir = "banner/uat/";
Map<String, String> respMap = null;
// 创建ossClient实例。
// OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
try {
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
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));
// 设置服务端返回200状态码,默认返回204。
respMap.put("success_action_status","200");
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
}
return (LinkedHashMap<String, String>) respMap;
}
<el-form-item label="上传图片" :prop="image" :rules="rules.image">
<SingleUpload v-model="image"></SingleUpload>
</el-form-item>
import SingleUpload from "@/views/subupload";
子组件:
<template>
<div>
<el-upload
class="avatar-uploader"
:data="dataObj"
action="https://ron-test.oss-cn-shanghai.aliyuncs.com"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
</template>
<script>
import { policy } from "@/api/upload";
export default {
name: "singleUpload",
props: {
value: String
},
computed: {
imageUrl() {
return this.value;
}
},
data() {
return {
// imageUrl: "",
dataObj: {
accessId: "",
policy: "",
signature: "",
dir: "",
host: "",
expire: ""
}
};
},
methods: {
emitInput(val) {
this.$emit("input", val);
},
handleAvatarSuccess(file) {
console.log("上传成功", file);
// this.imageUrl = URL.createObjectURL(file.raw);
this.emitInput(
// 将图片路径传给父组件
this.dataObj.host + "/" + this.dataObj.key.replace("${filename}", file.name)
);
},
beforeAvatarUpload(file) {
console.log(file);
let _self = this;
return policy()
.then(response => {
console.log("响应的数据", response.data);
_self.dataObj.policy = response.data.policy;
_self.dataObj.signature = response.data.signature;
_self.dataObj.ossaccessKeyId = response.data.accessId;
_self.dataObj.key = response.data.dir + "random" + file.name;
_self.dataObj.dir = response.data.dir;
_self.dataObj.host = response.data.host;
// 设置服务端返回200状态码,默认返回204。
_self.dataObj.success_action_status = response.data.success_action_status;
console.log("响应的数据222。。。", _self.dataObj);
})
.catch(err => {
console.log("error", err);
});
}
},
created() {},
mounted() {}
};
</script>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
</style>
字段 | 描述 |
---|---|
accessId | 用户请求的AccessKey ID |
policy | 用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串 |
signature | 对Policy签名后的字符串 |
dir | 限制上传的文件前缀 |
host | 用户发送上传请求的域名 说明:host不支持自定义域名 |
expire | 由服务器端指定的Policy过期时间,格式为Unix时间戳(自UTC时间1970年01月01号开始的秒数) |
与数据上传至服务器,再由服务器上传到oss相比:(Vue+element Upload利用http-request实现第三方地址图片上传)