|
@@ -2,7 +2,10 @@ package com.qmth.boot.core.fss.utils;
|
|
|
|
|
|
import com.qmth.boot.tools.codec.CodecUtils;
|
|
|
import com.qmth.boot.tools.models.ByteArray;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.net.URLEncoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.time.Duration;
|
|
@@ -15,10 +18,19 @@ import java.util.SimpleTimeZone;
|
|
|
*/
|
|
|
public class OssSigner {
|
|
|
|
|
|
+ private static final String[] ENCODED_CHARACTERS_WITH_SLASHES = new String[] { "+", "*", "%7E", "%2F" };
|
|
|
+
|
|
|
+ private static final String[] ENCODED_CHARACTERS_WITH_SLASHES_REPLACEMENTS = new String[] { "%20", "%2A", "~",
|
|
|
+ "/" };
|
|
|
+
|
|
|
+ private static final String[] ENCODED_CHARACTERS_WITHOUT_SLASHES = new String[] { "+", "*", "%7E" };
|
|
|
+
|
|
|
+ private static final String[] ENCODED_CHARACTERS_WITHOUT_SLASHES_REPLACEMENTS = new String[] { "%20", "%2A", "~" };
|
|
|
+
|
|
|
public static String buildHeader(OssConfig config, String method, String path, OssApiParam param) {
|
|
|
String dateString = getIso8601Date(param.getDate());
|
|
|
String dateTime = getIso8601DateTime(param.getDate());
|
|
|
- String uri = "/" + config.getBucket() + "/" + path;
|
|
|
+ String uri = urlEncode("/" + config.getBucket() + "/" + path, true);
|
|
|
// 步骤1:构造CanonicalRequest
|
|
|
String canonicalRequest = method.toUpperCase() + "\n" + uri + "\n\n" + (param.getContentMd5() != null ?
|
|
|
"content-md5:" + param.getContentMd5() + "\n" :
|
|
@@ -61,12 +73,14 @@ public class OssSigner {
|
|
|
String dateString = getIso8601Date(date);
|
|
|
String dateTime = getIso8601DateTime(date);
|
|
|
long expire = expireDuration.getSeconds();
|
|
|
+ String uri = urlEncode("/" + config.getBucket() + "/" + path, true);
|
|
|
// 步骤1:构造CanonicalRequest。
|
|
|
- String canonicalRequest = method.toUpperCase() + "\n" + "/" + config.getBucket() + "/" + path + "\n"
|
|
|
- + "x-oss-additional-headers=host&x-oss-credential=" + config.getAccessKey() + "%2F" + dateString + "%2F"
|
|
|
- + config.getRegion() + "%2Foss%2Faliyun_v4_request&x-oss-date=" + dateTime + "&x-oss-expires=" + expire
|
|
|
- + "&x-oss-signature-version=OSS4-HMAC-SHA256\n" + "host:" + config.getPortalHost() + "\n" + "\n"
|
|
|
- + "host\n" + "UNSIGNED-PAYLOAD";
|
|
|
+ String canonicalRequest =
|
|
|
+ method.toUpperCase() + "\n" + uri + "\n" + "x-oss-additional-headers=host&x-oss-credential=" + config
|
|
|
+ .getAccessKey() + "%2F" + dateString + "%2F" + config.getRegion()
|
|
|
+ + "%2Foss%2Faliyun_v4_request&x-oss-date=" + dateTime + "&x-oss-expires=" + expire
|
|
|
+ + "&x-oss-signature-version=OSS4-HMAC-SHA256\n" + "host:" + config.getPortalHost() + "\n" + "\n"
|
|
|
+ + "host\n" + "UNSIGNED-PAYLOAD";
|
|
|
String canonicalDigest = ByteArray.sha256(canonicalRequest).toHexString().toLowerCase();
|
|
|
// 步骤2:构造待签名字符串(StringToSign)。
|
|
|
String stringToSign = "OSS4-HMAC-SHA256\n" + dateTime + "\n" + dateString + "/" + config.getRegion()
|
|
@@ -94,6 +108,23 @@ public class OssSigner {
|
|
|
return queryString;
|
|
|
}
|
|
|
|
|
|
+ public static String urlEncode(String value, boolean ignoreSlashes) {
|
|
|
+ if (value == null) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ String encoded = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
|
|
+ if (!ignoreSlashes) {
|
|
|
+ return StringUtils.replaceEach(encoded, ENCODED_CHARACTERS_WITHOUT_SLASHES,
|
|
|
+ ENCODED_CHARACTERS_WITHOUT_SLASHES_REPLACEMENTS);
|
|
|
+ }
|
|
|
+ return StringUtils.replaceEach(encoded, ENCODED_CHARACTERS_WITH_SLASHES,
|
|
|
+ ENCODED_CHARACTERS_WITH_SLASHES_REPLACEMENTS);
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
+ throw new IllegalArgumentException("FailedToEncodeUri", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public static String getIso8601Date(Date date) {
|
|
|
SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd", Locale.US);
|
|
|
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
|