소스 검색

修改core-fss,修复使用oss模式下文件名含中文时的签名报错问题

Signed-off-by: luoshi <luoshi@qmth.com.cn>
luoshi 7 달 전
부모
커밋
d774c3dcef

+ 37 - 6
core-fss/src/main/java/com/qmth/boot/core/fss/utils/OssSigner.java

@@ -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"));

+ 15 - 11
core-fss/src/test/java/com/qmth/boot/test/core/fss/OssStoreTest.java

@@ -5,9 +5,9 @@ import com.qmth.boot.core.fss.utils.OssConfig;
 import com.qmth.boot.tools.models.ByteArray;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Assert;
-import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
+import java.io.File;
 import java.time.Duration;
 
 public class OssStoreTest {
@@ -20,7 +20,7 @@ public class OssStoreTest {
 
     private String config_local = "oss://key:secret@test.oss-api.qmth.com.cn";
 
-    @Test
+    //@Test
     public void test() throws Exception {
         OssStore store = new OssStore(new OssConfig(config_cloud, server_cloud), System.getProperty("java.io.tmpdir"));
         String content = RandomStringUtils.random(128, true, true);
@@ -28,16 +28,20 @@ public class OssStoreTest {
         store.write("/test/randome", new ByteArrayInputStream(data.value()), ByteArray.md5(data.value()).toHexString());
         Assert.assertTrue(store.exist("test/randome"));
         Assert.assertEquals(content, ByteArray.fromInputStream(store.read("test/randome")).toString());
-        String url = store.getServerUrl("/test/randome", Duration.ofMinutes(5));
+
+        data = ByteArray.fromFile(new File("/Users/luoshi/Downloads/test.pdf"));
+        store.write("/test/test.pdf", new ByteArrayInputStream(data.value()),
+                ByteArray.md5(data.value()).toHexString());
+        data = ByteArray.fromFile(new File("/Users/luoshi/Downloads/test.json"));
+        store.write("/test/test.json", new ByteArrayInputStream(data.value()),
+                ByteArray.md5(data.value()).toHexString());
+        data = ByteArray.fromFile(new File("/Users/luoshi/Downloads/test.zip"));
+        store.write("/test/测试.zip", new ByteArrayInputStream(data.value()), ByteArray.md5(data.value()).toHexString());
+        Assert.assertTrue(store.exist("test/测试.zip"));
+        String url = store.getServerUrl("/test/测试.zip", Duration.ofMinutes(5));
         //System.out.println(url);
-        Assert.assertEquals(content, ByteArray.fromUrl(url).toString());
-
-        //        data = ByteArray.fromFile(new File("/Users/luoshi/Downloads/test.pdf"));
-        //        store.write("/test/test.pdf", new ByteArrayInputStream(data.value()),
-        //                ByteArray.md5(data.value()).toHexString());
-        //        data = ByteArray.fromFile(new File("/Users/luoshi/Downloads/test.json"));
-        //        store.write("/test/test.json", new ByteArrayInputStream(data.value()),
-        //                ByteArray.md5(data.value()).toHexString());
+        Assert.assertEquals(data.toHexString(), ByteArray.fromUrl(url).toHexString());
+
         store.close();
     }