1.准备项目环境,搭建springboot工程
2.调整maven的pom.xml,导入ks3相关jar包,依赖如下
<dependency> <groupId>com.ksyun</groupId> <artifactId>ks3-kss-java-sdk</artifactId> <version>0.8.11</version> </dependency> <!-- 模拟请求 --> <dependency> <groupId>com.mashape.unirest</groupId> <artifactId>unirest-java</artifactId> <version>1.4.9</version> </dependency>
3.代码实现
application.xml
Ks3 config
ks3:
accessKey: XXXX
secretKey: XXXX
endPoint: ks3-cn-beijing.ksyun.com
bucketName: xxxxx
host: xxxxxx
package com.xy.quickapp.aidiscern.util;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
-
@author: kang.zou
-
@date:2019/8/7
-
AWS V4 签名处理工具
-
参考链接:https://docs.aws.amazon.com/zh_cn/general/latest/gr/sigv4_signing.html
*/
public class AWSAuth {
private AWSAuth() {
}public static class Builder {
private String accessKeyID; private String secretAccessKey; private String regionName; private String serviceName; private String httpMethodName; private String canonicalURI; private TreeMap<String, String> queryParametes; private TreeMap<String, String> awsHeaders; private String payload; private boolean debug = false; public Builder(String accessKeyID, String secretAccessKey) { this.accessKeyID = accessKeyID; this.secretAccessKey = secretAccessKey; } public Builder regionName(String regionName) { this.regionName = regionName; return this; } public Builder serviceName(String serviceName) { this.serviceName = serviceName; return this; } public Builder httpMethodName(String httpMethodName) { this.httpMethodName = httpMethodName; return this; } public Builder canonicalURI(String canonicalURI) { this.canonicalURI = canonicalURI; return this; } public Builder queryParametes(TreeMap<String, String> queryParametes) { this.queryParametes = queryParametes; return this; } public Builder awsHeaders(TreeMap<String, String> awsHeaders) { this.awsHeaders = awsHeaders; return this; } public Builder payload(String payload) { this.payload = payload; return this; } public Builder debug() { this.debug = true; return this; } public AWSAuth build() { return new AWSAuth(this); }
}
private String accessKeyID;
private String secretAccessKey;
private String regionName;
private String serviceName;
private String httpMethodName;
private String canonicalURI;
private TreeMap<String, String> queryParametes;
private TreeMap<String, String> awsHeaders;
private String payload;
private boolean debug = false;/* Other variables */
private final String HMACAlgorithm = “AWS4-HMAC-SHA256”;
private final String aws4Request = “aws4_request”;
private String strSignedHeader;
private String xAmzDate;
private String currentDate;private AWSAuth(Builder builder) {
accessKeyID = builder.accessKeyID;
secretAccessKey = builder.secretAccessKey;
regionName = builder.regionName;
serviceName = builder.serviceName;
httpMethodName = builder.httpMethodName;
canonicalURI = builder.canonicalURI;
queryParametes = builder.queryParametes;
awsHeaders = builder.awsHeaders;
payload = builder.payload;
debug = builder.debug;/* Get current timestamp value.(UTC) */ xAmzDate = getTimeStamp(); currentDate = getDate();
}
/**
-
任务 1:针对签名版本 4 创建规范请求
-
@return
*/
private String prepareCanonicalRequest() {
StringBuilder canonicalURL = new StringBuilder("");/* Step 1.1 以HTTP方法(GET, PUT, POST, etc.)开头, 然后换行. */
canonicalURL.append(httpMethodName).append("\n");/* Step 1.2 添加URI参数,换行. */
canonicalURI = canonicalURI == null || canonicalURI.trim().isEmpty() ? “/” : canonicalURI;
canonicalURL.append(canonicalURI).append("\n");/* Step 1.3 添加查询参数,换行. */
StringBuilder queryString = new StringBuilder("");
if (queryParametes != null && !queryParametes.isEmpty()) {
for (Map.Entry<String, String> entrySet : queryParametes.entrySet()) {
String key = entrySet.getKey();
String value = entrySet.getValue();
queryString.append(key).append("=").append(encodeParameter(value)).append("&");
}queryString.deleteCharAt(queryString.lastIndexOf("&")); queryString.append("\n");
} else {
queryString.append("\n");
}
canonicalURL.append(queryString);/* Step 1.4 添加headers, 每个header都需要换行. */
StringBuilder signedHeaders = new StringBuilder("");
if (awsHeaders != null && !awsHeaders.isEmpty()) {
for (Map.Entry<String, String> entrySet : awsHeaders.entrySet()) {
String key = entrySet.getKey();
String value = entrySet.getValue();
signedHeaders.append(key).append(";");
canonicalURL.append(key).append("😊.append(value).append("\n");
}
canonicalURL.append("\n");
} else {
canonicalURL.append("\n");
}/* Step 1.5 添加签名的headers并换行. */
strSignedHeader = signedHeaders.substring(0, signedHeaders.length() – 1); // 删掉最后的 “;”
canonicalURL.append(strSignedHeader).append("\n");/* Step 1.6 对HTTP或HTTPS的body进行SHA256处理. */
payload = payload == null ? “” : payload;
canonicalURL.append(generateHex(payload));return canonicalURL.toString();
}
/**
-
任务 2:创建签名版本 4 的待签字符串
-
@param canonicalURL
-
@return
*/
private String prepareStringToSign(String canonicalURL) {
String stringToSign = “”;/* Step 2.1 以算法名称开头,并换行. */
stringToSign = HMACAlgorithm + “\n”;/* Step 2.2 添加日期,并换行. */
stringToSign += xAmzDate + “\n”;/* Step 2.3 添加认证范围,并换行. */
stringToSign += currentDate + “/” + regionName + “/” + serviceName + “/” + aws4Request + “\n”;/* Step 2.4 添加任务1返回的规范URL哈希处理结果,然后换行. */
stringToSign += generateHex(canonicalURL);return stringToSign;
}
/**
-
任务 3:为 AWS Signature 版本 4 计算签名
-
@param stringToSign
-
@return
/
private String calculateSignature(String stringToSign) {
try {
/ Step 3.1 生成签名的key */
byte[] signatureKey = getSignatureKey(secretAccessKey, currentDate, regionName, serviceName);/* Step 3.2 计算签名. */ byte[] signature = HmacSHA256(signatureKey, stringToSign); /* Step 3.2.1 对签名编码处理 */ String strHexSignature = bytesToHex(signature); return strHexSignature;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
*任务 4:将签名信息添加到请求并返回headers
*-
@return
*/
public Map<String, String> getHeaders1() {
awsHeaders.put(“x-amz-date”, xAmzDate);/* 执行任务 1: 创建aws v4签名的规范请求字符串. */
String canonicalURL = prepareCanonicalRequest();/* 执行任务 2: 创建用来认证的字符串 4. */
String stringToSign = prepareStringToSign(canonicalURL);/* 执行任务 3: 计算签名. */
String signature = calculateSignature(stringToSign);if (signature != null) {
Map<String, String> header = new HashMap<String, String>(0);
header.put(“x-amz-date”, xAmzDate);
header.put(“Authorization”, buildAuthorizationString(signature));
return header;
} else {
return null;
}
}
/**
- 连接前几步处理的字符串生成Authorization header值.
- @param strSignature
- @return
*/
private String buildAuthorizationString(String strSignature) {
return HMACAlgorithm + " "
+ “Credential=” + accessKeyID + “/” + getDate() + “/” + regionName + “/” + serviceName + “/” + aws4Request + ", "
+ “SignedHeaders=” + strSignedHeader + ", "
+ “Signature=” + strSignature;
}
/**
- 将字符串16进制化.
- @param data
- @return
*/
private String generateHex(String data) {
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance(“SHA-256”);
messageDigest.update(data.getBytes(“UTF-8”));
byte[] digest = messageDigest.digest();
return String.format("%064x", new java.math.BigInteger(1, digest));
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
- 以给定的key应用HmacSHA256算法处理数据.
- @param data
- @param key
- @return
- @throws Exception
- @reference:
- http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
*/
private byte[] HmacSHA256(byte[] key, String data) throws Exception {
String algorithm = “HmacSHA256”;
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes(“UTF-8”));
}
/**
- 生成AWS 签名
- @param key
- @param date
- @param regionName
- @param serviceName
- @return
- @throws Exception
- @reference
- http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
*/
private byte[] getSignatureKey(String key, String date, String regionName, String serviceName) throws Exception {
byte[] kSecret = (“AWS4” + key).getBytes(“UTF8”);
byte[] kDate = HmacSHA256(kSecret, date);
byte[] kRegion = HmacSHA256(kDate, regionName);
byte[] kService = HmacSHA256(kRegion, serviceName);
byte[] kSigning = HmacSHA256(kService, aws4Request);
return kSigning;
}
final protected static char[] hexArray = “0123456789ABCDEF”.toCharArray();
/**
- 将字节数组转换为16进制字符串
- @param bytes
- @return
*/
private String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars).toLowerCase();
}
/**
- 获取yyyyMMdd’T’HHmmss’Z’格式的当前时间
- @return
*/
private String getTimeStamp() {
DateFormat dateFormat = new SimpleDateFormat(“yyyyMMdd’T’HHmmss’Z’”);
dateFormat.setTimeZone(TimeZone.getTimeZone(“UTC”));//server timezone
return dateFormat.format(new Date());
}
/**
- 获取yyyyMMdd格式的当前日期
- @return
*/
private String getDate() {
DateFormat dateFormat = new SimpleDateFormat(“yyyyMMdd”);
dateFormat.setTimeZone(TimeZone.getTimeZone(“UTC”));//server timezone
return dateFormat.format(new Date());
}
/**
- UTF-8编码
- @param param
- @return
*/
private String encodeParameter(String param){
try {
return URLEncoder.encode(param, “UTF-8”);
} catch (Exception e) {
return URLEncoder.encode(param);
}
}
}
-
package com.xy.quickapp.aidiscern.config;
import com.ksyun.ks3.http.HttpClientConfig;
import com.ksyun.ks3.service.Ks3;
import com.ksyun.ks3.service.Ks3Client;
import com.ksyun.ks3.service.Ks3ClientConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
-
Created by kang.zou
-
on 2020/2/11
*/
@Configuration
public class Ks3Config {@Value("${ks3.accessKey}")
private String accessKey;@Value("${ks3.secretKey}")
private String secretKey;@Value("${ks3.endPoint}")
private String endPoint;@Value("${ks3.bucketName}")
private String bucketName;@Value("${ks3.host}")
private String host;private String basePath;
public String getAccessKey() {
return accessKey;
}public String getSecretKey() {
return secretKey;
}public String getEndPoint() {
return endPoint;
}public String getBucketName() {
return bucketName;
}public String getHost() {
return host;
}@Bean(name = “ks3Client”)
public Ks3 ks3Client() {
Ks3ClientConfig config = new Ks3ClientConfig();
/**
-
设置服务地址
-
中国(北京)| ks3-cn-beijing.ksyun.com
-
中国(上海)| ks3-cn-shanghai.ksyun.com
-
中国(香港)| ks3-cn-hk-1.ksyun.com
-
中国(杭州)| kss.ksyun.com
-
中国(广州)| ks3-cn-guangzhou.ksyun.com
-
中国(青岛)| ks3-cn-qingdao.ksyun.com
-
金融专区(北京)| ks3-jr-beijing.ksyun.com
-
金融专区(上海)| ks3-jr-shanghai.ksyun.com
-
俄罗斯 | ks3-rus.ksyun.com
-
新加坡 | ks3-sgp.ksyun.com
-
如果使用自定义域名,设置endpoint为自定义域名,同时设置domainMode为true
config.setEndpoint(endPoint); //此处以北京region为例
/**
*true:表示以自定义域名访问
*false:表示以KS3的外网域名或内网域名访问,默认为false
config.setDomainMode(false); config.setProtocol(Ks3ClientConfig.PROTOCOL.http);
/**
*true表示以 endpoint/{bucket}/{key}的方式访问
*false表示以 {bucket}.endpoint/{key}的方式访问
*如果domainMode设置为true,pathStyleAccess可忽略设置
config.setPathStyleAccess(false); HttpClientConfig hconfig = new HttpClientConfig();
//在HttpClientConfig中可以设置httpclient的相关属性,比如代理,超时,重试等。
config.setHttpClientConfig(hconfig); Ks3 client = new Ks3Client(accessKey,secretKey,config); return client; }
package com.xy.quickapp.aidiscern.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ksyun.ks3.dto.CannedAccessControlList;
import com.ksyun.ks3.dto.ObjectMetadata;
import com.ksyun.ks3.service.Ks3;
import com.ksyun.ks3.service.request.PutObjectRequest;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.xy.quickapp.aidiscern.config.Ks3Config;
import com.xy.quickapp.aidiscern.domain.ModelResult;
import com.xy.quickapp.aidiscern.service.Ks3Service;
import com.xy.quickapp.aidiscern.util.AWSAuth;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;
/**
-
Created by kang.zou
-
on 2020/2/11
*/
@Service
public class Ks3ServiceImpl implements Ks3Service {
private static final Logger log = LoggerFactory.getLogger(Ks3ServiceImpl.class);@Autowired
private Ks3Config ks3Config;@Autowired
private Ks3 ks3Client;@Override
public ModelResult uploadFile(InputStream inputStream, String path, String fileName) {
JSONObject imgInfo = new JSONObject();
try {
ObjectMetadata meta = new ObjectMetadata();
PutObjectRequest request = new PutObjectRequest(ks3Config.getBucketName(),path, inputStream,meta);
request.setCannedAcl(CannedAccessControlList.PublicRead);
ks3Client.putObject(request);
} catch (Exception e) {
log.error(“上传异常:{}”, e.getMessage());
return new ModelResult<>(null).withError(“20001”, “上传文件失败”);
}
imgInfo.put(“fileName”, fileName);
imgInfo.put(“imgUrl”, “https://cdn-qapp.bizport.cn/”+path);
return new ModelResult<>(imgInfo);
}@Override
public ModelResult deleteFile(String locationPath) throws UnirestException {
try {
ks3Client.deleteObject(ks3Config.getBucketName(), locationPath);
} catch (Exception e) {
log.error(“删除异常:{}”, e.getMessage());
return new ModelResult<>(null).withError(“20001”, “删除文件异常”);
}
JSONObject refreshObj = new JSONObject();
JSONArray files = new JSONArray();
JSONObject fileObj = new JSONObject();
fileObj.put(“Url”, “https://cdn-qapp.bizport.cn/”+locationPath);
files.add(fileObj);
refreshObj.put(“Files”, files);
int status = refreshCDN(refreshObj.toJSONString());
if(status != 200) {
log.info(“刷新CDN缓存失败”);
}
return new ModelResult<>(Boolean.TRUE);
}/**
-
刷新CDN缓存
-
参考链接: https://docs.ksyun.com/documents/215
-
@param dealFiles 待处理文件/文件夹
-
{"Files":[{"Url":"http://test.dxz.ksyun.8686c.com/abc.txt"}],"Dirs":[{"Url":"https://cdn-qapp.bizport.cn/images"}]}
-
@return 状态码
*/
private int refreshCDN(String dealFiles) throws UnirestException {
String uri = “/2016-09-01/content/RefreshCaches”;
String accessKey = ks3Config.getAccessKey();
String secretKey = ks3Config.getSecretKey();TreeMap<String, String> params = new TreeMap<String, String>();
params.put(“Content-Type”, “application/json”);
params.put(“Action”, “RefreshCaches”);
params.put(“Version”, “2016-09-01”);
params.put(“Accept”, “application/json”);TreeMap<String, String> awsHeaders = new TreeMap<String, String>();
awsHeaders.put(“Host”, “cdn.api.ksyun.com”);
awsHeaders.put(“Content-Length”, “”+ StringUtils.length(dealFiles));
awsHeaders.put(“Content-Type”, “application/json”);
awsHeaders.put(“X-Amz-Date”, getTimeStamp());Map<String, String> header = new AWSAuth.Builder(accessKey, secretKey)
.regionName(“cn-beijing-6”)
.serviceName(“cdn”)
.httpMethodName(“POST”)
.canonicalURI(uri)
.queryParametes(params)
.awsHeaders(awsHeaders)
.payload(dealFiles)
.debug()
.build()
.getHeaders1();HttpResponse response = Unirest.post(“http://cdn.api.ksyun.com/2016-09-01/content/RefreshCaches?Content-Type=application%2Fjson&Action=RefreshCaches&Version=2016-09-01&Accept=application%2Fjson”)
.header(“content-type”, “application/json”)
.header(“host”, “cdn.api.ksyun.com”)
.header(“x-amz-date”, header.get(“x-amz-date”))
.header(“authorization”, header.get(“Authorization”))
.body(dealFiles)
.asString();return response.getStatus();
}
private String getTimeStamp() {
DateFormat dateFormat = new SimpleDateFormat(“yyyyMMdd’T’HHmmss’Z’”);
dateFormat.setTimeZone(TimeZone.getTimeZone(“UTC”));
return dateFormat.format(new Date());
} -
原文链接:https://blog.csdn.net/weixin_42649343/article/details/104313533?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165918469516782390592771%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165918469516782390592771&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-27-104313533-null-null.nonecase&utm_term=%E9%A6%99%E6%B8%AFcdn
原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/4660