获取sts临时凭证的java接口
/**
* sts api
* @author lpd
*/
@RestController
@RequestMapping("/api/oss")
public class OssStsApiController extends AbstractController {
/**
* oss服务注入
*/
@Autowired
private OssProperties ossProperties;
/**
* LOGGER
*/
private static final Logger LOGGER = LoggerFactory.getLogger(OssStsApiController.class);
/***
* 获取临时凭证
* @return
*/
@GetMapping("/sts")
public CommonResponse sts() throws com.aliyuncs.exceptions.ClientException {
CommonResponse commonResponse = CommonResponse.createCommonResponse();
// STS服务接入点,例如sts.cn-hangzhou.aliyuncs.com。您可以通过公网或者VPC接入STS服务。
String endpoint = "sts.cn-hangzhou.aliyuncs.com";
// 从环境变量中获取步骤1生成的RAM用户的访问密钥(AccessKey ID和AccessKey Secret)。
// oss的key和密钥
String accessKeyId = ossProperties.getWebAccessKeyId();
String accessKeySecret = ossProperties.getWebAccessKeySecret();
// 从环境变量中获取步骤3生成的RAM角色的RamRoleArn。
String roleArn = ossProperties.getWebAcs();
// 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。
String roleSessionName = "Session";
// 临时访问凭证将获得角色拥有的所有权限。
String policy = null;
// 临时访问凭证的有效时间,单位为秒。最小值为900,最大值以当前角色设定的最大会话时间为准。当前角色最大会话时间取值范围为3600秒~43200秒,默认值为3600秒。
// 在上传大文件或者其他较耗时的使用场景中,建议合理设置临时访问凭证的有效时间,确保在完成目标任务前无需反复调用STS服务以获取临时访问凭证。
Long durationSeconds = 1800L;
try {
// 发起STS请求所在的地域。建议保留默认值,默认值为空字符串("")。
String regionId = "";
// 添加endpoint。适用于Java SDK 3.12.0及以上版本。
DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
// 添加endpoint。适用于Java SDK 3.12.0以下版本。
// DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
// 构造default profile。
IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
// 构造client。
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
// 适用于Java SDK 3.12.0及以上版本。
request.setSysMethod(MethodType.POST);
// 适用于Java SDK 3.12.0以下版本。
// request.setMethod(MethodType.POST);
request.setRoleArn(roleArn);
request.setRoleSessionName(roleSessionName);
request.setPolicy(policy);
request.setDurationSeconds(durationSeconds);
final AssumeRoleResponse response = client.getAcsResponse(request);
LOGGER.warn("tempAccessKeyId:" + response.getCredentials().getAccessKeyId());
LOGGER.warn("tempSecretAccessKey:" + response.getCredentials().getAccessKeySecret());
LOGGER.warn("sessionToken:" + response.getCredentials().getSecurityToken());
OssStsResponseInfo ossStsResponseInfo = new OssStsResponseInfo();
ossStsResponseInfo.setSessionToken(response.getCredentials().getSecurityToken());
ossStsResponseInfo.setTempAccessKeyId(response.getCredentials().getAccessKeyId());
ossStsResponseInfo.setTempSecretAccessKey(response.getCredentials().getAccessKeySecret());
commonResponse.setData(ossStsResponseInfo);
return commonResponse;
} catch (ClientException e) {
LOGGER.error("RequestId: " + e.getRequestId());
}
return null;
}
}
前端代码:
npm install js-md5 --save
npm install ali-oss --save
<el-upload
class="upload-demo"
drag
action="https://jsonplaceholder.typicode.com/posts/"
accept=".rar,.zip,.dwg,.dxf,.pdf,.stp,.step,.doc,.docx,.sldprt,.sldasm"
:format = fileType
:on-error="videoHandleError"
:on-change="handleFileChange"
:before-upload="beforeAvatarUpload">
<div class="el-upload__text" style="margin-top: 16px;">
<span v-if="dataFileName === ''">将文件拖到此处,或<em>点击上传</em></span>
<span v-else>{{dataFileName}} <em>重新上传</em></span>
</div>
<div class="el-upload__text" style="margin-top: 14px;">
<span style="color: #999999;font-size: 12px;">
<div>文件大小:1024MB</div>
</span>
</div>
</el-upload>
<!-- :on-change="handleFileChange"-->
<div style="line-height: 30px;color: #f07d7d;font-size: 12px;">上传格式:.rar .zip .dwg .dxf .pdf .doc .docx .pdf .stp .step .sldprt .sldasm </div>
<el-progress text-color="#ffffff" :percentage="uploadProgress" :text-inside="true" :stroke-width="20"
style="width: 320px;"></el-progress>
import OSS from "ali-oss";
import md5 from 'js-md5';
// 字符串截取
truncateString(str, prefixLength, suffixLength) {
const totalLength = prefixLength + suffixLength + 3; // 3 characters for "..."
if (str.length <= totalLength) {
// If the string is short enough, return it as is.
return str;
}
const prefix = str.substring(0, prefixLength);
const suffix = str.substring(str.length - suffixLength);
return `${prefix}...${suffix}`;
},
videoHandleError(){
// 上传失败
const that = this;
that.$message({
message: '上传失败!',
type: 'error',
duration: 1 * 1000
});
},
// 生成和后台对应md5
calculateFileMD5(file) {
return new Promise((resolve, reject) => {
// 创建一个FileReader实例
const reader = new FileReader();
// 当文件读取完成时触发
reader.onload = (e) => {
// 使用js-md5库计算读取到的文件的MD5
const hash = md5(e.target.result);
resolve(hash);
};
// 当读取文件出错时触发
reader.onerror = (error) => {
reject(error);
};
// 读取文件内容为二进制字符串
reader.readAsArrayBuffer(file);
});
},
// 选择文件后开始上传
handleFileChange(file,fileList) {
const that = this;
const fieldExtensions = file.name.split(".").pop();
if(!that.fileType.includes(fieldExtensions)){
return false;
}
if(file.size > 1024 * 1024 * 1024){
return false;
}
if(that.submitUploadDisabled){
that.$message({
message: '正在上传,请勿重复上传!',
type: 'error',
duration: 2 * 1000
});
return false;
}else {
// 先计算文件的MD5
that.calculateFileMD5(file.raw).then(md5 => {
that.resMd5 = md5;
that.form.fileMd5 = md5
// 判断md5是否存在
this.$axios.get(ResourceCreation.getResourcesMd5,{
params: {md5: that.resMd5}
}).then(res => {
if(res === "成功"){
that.uploadedCount = 0;
that.submitUploadDisabled = true;
const lastDotIndex = file.name.lastIndexOf('.')
if(lastDotIndex === -1 || lastDotIndex === 0){
that.form.title = file.name;
}else {
that.form.title = file.name.slice(0,lastDotIndex);
}
// 简单上传
if(file.size < 5 * 1024 * 1024){
that.putObject(file);
}else {
// 分片上传
that.multipartUpload(file);
}
}else {
this.$message({
message: "请上传原创且不重复的资源!",
type: 'error'
});
return false
}
})
}).catch(error => {
console.error('Error calculating MD5:', error);
});
}
},
// 简单上传
async putObject(file) {
const that = this;
const fieldExtensions = file.name.split(".").pop();
const fileName = Date.now().toString() + "-" + this.loginUserId;
const objectName = '/resource/' + fileName + '.' +fieldExtensions;
const filePath = '/resource/' + fileName + '.' +fieldExtensions;
try {
const options = {
meta: { temp: "demo" },
mime: "json",
headers: { "Content-Type": "text/plain" },
};
const resultSts = await that.$axios.get(ResourceCreation.getSts);
if(resultSts === null){
that.$message({
message: '临时凭证获取失败,请稍后重试!',
type: 'error',
duration: 2 * 1000
});
return false;
}
const store = new OSS({
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: resultSts.tempAccessKeyId,
accessKeySecret: resultSts.tempSecretAccessKey,
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: resultSts.sessionToken,
// 填写Bucket所在地域。以华东1(杭州)为例,设置region为oss-cn-hangzhou。
region: "oss-cn-hangzhou",
// 填写Bucket名称,例如examplebucket。
bucket: "bucketName",
});
const result = await store.put(objectName, file.raw, options);
if(result.res.status === 200){
that.cnUgcUploadStatusInfo.title = file.name
that.cnUgcUploadStatusInfo.filePath = filePath
that.form.filePath = filePath
that.form.size = file.size
that.dataFileName = that.truncateString(file.name,18,18)
that.form.fileName = file.name
that.form.fileext = fieldExtensions
that.uploadProgress = 100
that.$axios.post(ResourceCreation.ugcUploadStatusInsert,that.cnUgcUploadStatusInfo).then(res => {
that.submitUploadDisabled = false;
})
// ugcUploadStatusInsert
}else {
that.$message({
message: '网络异常,请刷新页面后重新上传!',
type: 'error',
duration: 2 * 1000
});
return false;
}
} catch (e) {
console.log(e);
}
},
// 开始分片上传。
async multipartUpload(file) {
const that = this;
const options = {
// 获取分片上传进度、断点和返回值。
progress: (p, cpt, res) => {
that.uploadProgress = parseFloat((p * 100).toFixed(2));
},
// 设置并发上传的分片数量。
parallel: 4,
// 设置分片大小。默认值为1 MB,最小值为100 KB。
partSize: 1024 * 1024,
// headers,
// 自定义元数据,通过HeadObject接口可以获取Object的元数据。
meta: { year: 2020, people: "test" },
mime: "text/plain",
};
const fieldExtensions = file.name.split(".").pop();
const fileName = Date.now().toString() + "-" + this.loginUserId;
const objectName = '/resource/' + fileName + '.' +fieldExtensions;
const filePath = '/resource/' + fileName + '.' +fieldExtensions;
try {
const resultSts = await that.$axios.get(ResourceCreation.getSts);
if(resultSts === null){
that.$message({
message: '临时凭证获取失败,请稍后重试!',
type: 'error',
duration: 2 * 1000
});
return false;
}
const store = new OSS({
// 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。
accessKeyId: resultSts.tempAccessKeyId,
accessKeySecret: resultSts.tempSecretAccessKey,
// 从STS服务获取的安全令牌(SecurityToken)。
stsToken: resultSts.sessionToken,
// 填写Bucket所在地域。以华东1(杭州)为例,设置region为oss-cn-hangzhou。
region: "oss-cn-hangzhou",
// 填写Bucket名称,例如examplebucket。
bucket: "bucketName",
});
const result = await store.multipartUpload(objectName, file.raw, {
...options
});
if(result.res.status === 200){
that.cnUgcUploadStatusInfo.title = file.name
that.cnUgcUploadStatusInfo.filePath = filePath
that.form.filePath = filePath
that.dataFileName = that.truncateString(file.name,18,18)
that.form.size = file.size
that.form.fileName = file.name
that.form.fileext = fieldExtensions
that.$axios.post(ResourceCreation.ugcUploadStatusInsert,that.cnUgcUploadStatusInfo).then(res => {
that.submitUploadDisabled = false;
})
// ugcUploadStatusInsert
}else {
that.$message({
message: '网络异常,请刷新页面后重新上传!',
type: 'error',
duration: 2 * 1000
});
return false;
}
} catch (e) {
// 捕获超时异常。
if (e.code === 'ConnectionTimeoutError') {
console.log('TimeoutError');
// do ConnectionTimeoutError operation
}
console.log(e);
}
},
效果图:
上传1G大概不到2分钟的速度