You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by li...@apache.org on 2022/12/07 01:18:02 UTC

[shenyu] branch master updated: [type:refactor]Decoupled and enhanced SignUtil (#4234)

This is an automated email from the ASF dual-hosted git repository.

likeguo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 25aa30c1b [type:refactor]Decoupled and enhanced SignUtil (#4234)
25aa30c1b is described below

commit 25aa30c1b095176dcc5d4febeb5d2e46e997f4a2
Author: 愿凌飞 <ti...@foxmail.com>
AuthorDate: Wed Dec 7 09:17:52 2022 +0800

    [type:refactor]Decoupled and enhanced SignUtil (#4234)
    
    * [type:refactor]Decoupled and enhanced SignUtil
    
    * [type:refactor]fix test
    
    * refactor
    
    * refactor
    
    * fix
    
    * fix
    
    * fix
---
 .../org/apache/shenyu/common/utils/HmacUtils.java  |  66 ++++++++++++
 .../org/apache/shenyu/common/utils/MapUtils.java   |  27 +++--
 .../org/apache/shenyu/common/utils/SignUtils.java  |  77 ++++++--------
 .../apache/shenyu/common/utils/MapUtilsTest.java   |  31 +++---
 .../apache/shenyu/common/utils/SignUtilsTest.java  |  51 ++++-----
 .../test/http/combination/SignPluginTest.java      |  29 +++++-
 .../plugin/sign/api/DefaultSignProvider.java       |  26 ++++-
 .../plugin/sign/service/DefaultSignService.java    |   6 +-
 .../sign/service/DefaultSignServiceTest.java       |  26 ++++-
 .../plugin/sign/sign/DefaultSignProviderTest.java  |  10 +-
 .../web/controller/LocalPluginController.java      | 114 ++++++++++-----------
 11 files changed, 280 insertions(+), 183 deletions(-)

diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/utils/HmacUtils.java b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/HmacUtils.java
new file mode 100644
index 000000000..6450e70ff
--- /dev/null
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/HmacUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.common.utils;
+
+import org.apache.commons.codec.digest.HmacAlgorithms;
+
+/**
+ * HmacUtils.
+ */
+public class HmacUtils {
+
+    /**
+     * Returns a HmacMd5 Message Authentication Code (MAC) as hex string (lowercase).
+     *
+     * @param key           The key
+     * @param valueToDigest The value to use to digest
+     * @return Message Authentication Code
+     */
+    public static String hmacMd5Hex(final String key, final String valueToDigest) {
+        return getHmacHex(HmacAlgorithms.HMAC_MD5, key, valueToDigest);
+    }
+
+    /**
+     * Returns a HmacSha256 Message Authentication Code (MAC) as hex string (lowercase).
+     *
+     * @param key           The key
+     * @param valueToDigest The value to use to digest
+     * @return Message Authentication Code
+     */
+    public static String hmacSha256Hex(final String key, final String valueToDigest) {
+        return getHmacHex(HmacAlgorithms.HMAC_SHA_256, key, valueToDigest);
+
+    }
+
+    /**
+     * Returns a HmacSha512 Message Authentication Code (MAC) as hex string (lowercase).
+     *
+     * @param key           The key
+     * @param valueToDigest The value to use to digest
+     * @return Message Authentication Code
+     */
+    public static String hmacSha512Hex(final String key, final String valueToDigest) {
+        return getHmacHex(HmacAlgorithms.HMAC_SHA_512, key, valueToDigest);
+    }
+
+    private static String getHmacHex(final HmacAlgorithms algorithm, final String key, final String valueToDigest) {
+        return new org.apache.commons.codec.digest.HmacUtils(algorithm, key)
+                .hmacHex(valueToDigest);
+    }
+
+}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java
similarity index 60%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
copy to shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java
index af556da5b..b0801dd60 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/MapUtils.java
@@ -15,27 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.plugin.sign.api;
-
-import org.apache.shenyu.common.utils.SignUtils;
+package org.apache.shenyu.common.utils;
 
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
-/**
- * The Sign plugin default signer.
- */
-public class DefaultSignProvider implements SignProvider {
+public class MapUtils {
 
     /**
-     * acquired sign.
+     * Transform to string map.
      *
-     * @param signKey sign key
-     * @param jsonParams json params
-     * @param queryParams  url query params
-     * @return sign
+     * @param map source map
+     * @return string map
      */
-    @Override
-    public String generateSign(final String signKey, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
-        return SignUtils.generateSign(signKey, jsonParams, queryParams);
+    public static Map<String, String> transStringMap(final Map<String, Object> map) {
+        return Optional.ofNullable(map)
+                .map(m -> m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> Objects.toString(e.getValue(), null))))
+                .orElse(null);
     }
 }
diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/utils/SignUtils.java b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/SignUtils.java
index ae137c8bf..04830a345 100644
--- a/shenyu-common/src/main/java/org/apache/shenyu/common/utils/SignUtils.java
+++ b/shenyu-common/src/main/java/org/apache/shenyu/common/utils/SignUtils.java
@@ -17,53 +17,51 @@
 
 package org.apache.shenyu.common.utils;
 
-import java.util.Comparator;
+import com.google.common.collect.ImmutableMap;
+
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
-import java.util.stream.Collectors;
 
 /**
  * SignUtils.
  */
 public final class SignUtils {
 
-    /**
-     * acquired sign.
-     *
-     * @param signKey sign key
-     * @param jsonParams json params
-     * @param queryParams  url query params
-     * @return sign
-     */
-    public static String generateSign(final String signKey, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
-        final String jsonSign = Optional.ofNullable(jsonParams).map(e -> e.keySet().stream()
-                .sorted(Comparator.naturalOrder())
-                .map(key -> String.join("", key, jsonParams.get(key)))
-                .collect(Collectors.joining()).trim())
-                .orElse("");
-        final String querySign = Optional.ofNullable(queryParams).map(e -> e.keySet().stream()
-                .sorted(Comparator.naturalOrder())
-                .map(key -> String.join("", key, queryParams.get(key)))
-                .collect(Collectors.joining()).trim())
-                .orElse("");
-        final String sign = String.join("", jsonSign, querySign, signKey);
-        // TODO this is a risk for error charset coding with getBytes
-        return DigestUtils.md5Hex(sign.getBytes()).toUpperCase();
-    }
+    public static final String SIGN_MD5 = "MD5";
+
+    public static final String SIGN_HMD5 = "HMD5";
+
+    public static final String SIGN_HS256 = "HS256";
+
+    public static final String SIGN_HS512 = "HS512";
+
+    private static final Map<String, SignFunction> SIGN_FUNCTION_MAP = ImmutableMap.of(
+            SIGN_MD5, (key, data) -> DigestUtils.md5Hex(data + key),
+            SIGN_HMD5, HmacUtils::hmacMd5Hex,
+            SIGN_HS256, HmacUtils::hmacSha256Hex,
+            SIGN_HS512, HmacUtils::hmacSha512Hex
+    );
 
     /**
-     * isValid.
+     * Returns signature of data as hex string (lowercase).
      *
-     * @param sign    sign
-     * @param jsonParams json params
-     * @param queryParams  url query params
-     * @param signKey sign key
-     * @return boolean
+     * @param algorithmName the name of sign algorithm
+     * @param key           key
+     * @param data          data to sign
+     * @return signature
+     * @throws NullPointerException          if key or data is null
+     * @throws UnsupportedOperationException if algorithmName isn't supported
      */
-    public static boolean isValid(final String sign, final Map<String, String> jsonParams, final Map<String, String> queryParams, final String signKey) {
-        return Objects.equals(sign, generateSign(signKey, jsonParams, queryParams));
+    public static String sign(final String algorithmName, final String key, final String data) {
+        if (Objects.isNull(key) || Objects.isNull(data)) {
+            throw new NullPointerException("Key or data is null.");
+        }
+
+        return Optional.ofNullable(SIGN_FUNCTION_MAP.get(algorithmName))
+                .orElseThrow(() -> new UnsupportedOperationException("unsupported sign algorithm:" + algorithmName))
+                .sign(key, data);
     }
 
     /**
@@ -75,16 +73,9 @@ public final class SignUtils {
         return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
     }
 
-    /**
-     * Transform to string map.
-     *
-     * @param map source map
-     * @return string map
-     */
-    public static Map<String, String> transStringMap(final Map<String, Object> map) {
-        return Optional.ofNullable(map)
-                .map(m -> m.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> Objects.toString(e.getValue(), null))))
-                .orElse(null);
+    @FunctionalInterface
+    private interface SignFunction {
+        String sign(String key, String data);
     }
 
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java b/shenyu-common/src/test/java/org/apache/shenyu/common/utils/MapUtilsTest.java
similarity index 58%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
copy to shenyu-common/src/test/java/org/apache/shenyu/common/utils/MapUtilsTest.java
index af556da5b..29c097acc 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
+++ b/shenyu-common/src/test/java/org/apache/shenyu/common/utils/MapUtilsTest.java
@@ -15,27 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.shenyu.plugin.sign.api;
+package org.apache.shenyu.common.utils;
 
-import org.apache.shenyu.common.utils.SignUtils;
+import org.junit.jupiter.api.Test;
 
+import java.util.HashMap;
 import java.util.Map;
 
-/**
- * The Sign plugin default signer.
- */
-public class DefaultSignProvider implements SignProvider {
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class MapUtilsTest {
 
-    /**
-     * acquired sign.
-     *
-     * @param signKey sign key
-     * @param jsonParams json params
-     * @param queryParams  url query params
-     * @return sign
-     */
-    @Override
-    public String generateSign(final String signKey, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
-        return SignUtils.generateSign(signKey, jsonParams, queryParams);
+    @Test
+    public void testTransStringMap() {
+        Map<String, Object> jsonParams = new HashMap<>();
+        jsonParams.put("a", 1);
+        jsonParams.put("b", 2);
+        Map<String, String> stringStringMap = MapUtils.transStringMap(jsonParams);
+        assertEquals(stringStringMap.get("a").getClass(), String.class);
+        assertEquals(stringStringMap.get("a"), "1");
     }
 }
diff --git a/shenyu-common/src/test/java/org/apache/shenyu/common/utils/SignUtilsTest.java b/shenyu-common/src/test/java/org/apache/shenyu/common/utils/SignUtilsTest.java
index 08fd3d644..a1330f2a2 100644
--- a/shenyu-common/src/test/java/org/apache/shenyu/common/utils/SignUtilsTest.java
+++ b/shenyu-common/src/test/java/org/apache/shenyu/common/utils/SignUtilsTest.java
@@ -19,12 +19,10 @@ package org.apache.shenyu.common.utils;
 
 import org.junit.jupiter.api.Test;
 
-import java.util.HashMap;
-import java.util.Map;
-
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
 
 /**
  * Test cases for SignUtils.
@@ -32,40 +30,31 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 public final class SignUtilsTest {
 
     @Test
-    public void testGenerateSign() {
-        Map<String, String> jsonParams = new HashMap<>();
-        jsonParams.put("a", "1");
-        jsonParams.put("b", "2");
-        Map<String, String> queryParams = new HashMap<>();
-        jsonParams.put("a", "1");
-        jsonParams.put("b", "2");
-        assertNotNull(SignUtils.generateSign("test", jsonParams, queryParams));
+    public void testGenerateMd5Sign() {
+
+        assertThat(SignUtils.sign(SignUtils.SIGN_MD5, "test", "a1b2"),
+                is("7aa98f7d67f8e4730e2d1d3902295ce6"));
     }
 
     @Test
-    public void testValid() {
-        final String sign = "7AA98F7D67F8E4730E2D1D3902295CE6";
-        Map<String, String> jsonParams = new HashMap<>();
-        jsonParams.put("a", "1");
-        jsonParams.put("b", "2");
-        Map<String, String> queryParams = new HashMap<>();
-        jsonParams.put("a", "1");
-        jsonParams.put("b", "2");
-        assertTrue(SignUtils.isValid(sign, jsonParams, queryParams, "test"));
+    public void testGeneratesSignWithNullKeyOrNullData() {
+
+        assertThrowsExactly(NullPointerException.class,
+            () -> SignUtils.sign(SignUtils.SIGN_HS256, "key", null));
+
+        assertThrowsExactly(NullPointerException.class,
+            () -> SignUtils.sign(SignUtils.SIGN_HS256, null, "data"));
     }
 
     @Test
-    public void testGenerateKey() {
-        assertNotNull(SignUtils.generateKey());
+    public void testGeneratesSignWithUnsupportedAlgorithm() {
+
+        assertThrowsExactly(UnsupportedOperationException.class,
+            () -> SignUtils.sign("supported_algorithm", "key", "data"));
     }
 
     @Test
-    public void testTransStringMap() {
-        Map<String, Object> jsonParams = new HashMap<>();
-        jsonParams.put("a", "1");
-        jsonParams.put("b", "2");
-        Map<String, String> stringStringMap = SignUtils.transStringMap(jsonParams);
-        assertEquals(stringStringMap.get("a").getClass(), String.class);
-        assertEquals(stringStringMap.get("a"), "1");
+    public void testGenerateKey() {
+        assertNotNull(SignUtils.generateKey());
     }
 }
diff --git a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java
index 2bedcb367..edc19529a 100644
--- a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java
+++ b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java
@@ -38,8 +38,11 @@ import org.junit.jupiter.api.Test;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -173,8 +176,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
 
     private Map<String, Object> buildHeadersMap(final String timestamp, final String path, final String appKey,
                                                 final String appSecret, final String version) {
-        String extSignKey = String.join("", Constants.PATH, path, Constants.TIMESTAMP, timestamp, Constants.VERSION, version, appSecret);
-        String sign = SignUtils.generateSign(extSignKey, null, null);
+        String sign = buildSign(appSecret, version, timestamp, path, null, null);
         Map<String, Object> headers = Maps.newHashMapWithExpectedSize(4);
         headers.put("timestamp", timestamp);
         headers.put("appKey", appKey);
@@ -185,9 +187,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
 
     private Map<String, Object> buildHeadersMapQueryParam(final String timestamp, final String path, final String appKey,
                                                           final String appSecret, final String version, final Map<String, String> queryParam) {
-        String extSignKey = String.join("", Constants.PATH, path, Constants.TIMESTAMP, timestamp, Constants.VERSION, version, appSecret);
-        String sign = SignUtils.generateSign(extSignKey, null, queryParam);
-
+        String sign = buildSign(appSecret, version, timestamp, path, null, queryParam);
         Map<String, Object> headers = Maps.newHashMapWithExpectedSize(4);
         headers.put("timestamp", timestamp);
         headers.put("appKey", appKey);
@@ -258,4 +258,23 @@ public final class SignPluginTest extends AbstractPluginDataInit {
         cleanPluginData(PluginEnum.SIGN.getName());
         cleanAuthData(APP_KEY);
     }
+
+    private String buildSign(final String signKey, final String version, final String timeStamp, final String path, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
+
+        final String jsonSign = Optional.ofNullable(jsonParams).map(e -> e.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .map(key -> String.join("", key, jsonParams.get(key)))
+                .collect(Collectors.joining()).trim())
+                .orElse("");
+
+        final String querySign = Optional.ofNullable(queryParams).map(e -> e.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .map(key -> String.join("", key, queryParams.get(key)))
+                .collect(Collectors.joining()).trim())
+                .orElse("");
+
+        final String extSignKey = String.join("", Constants.PATH, path, Constants.TIMESTAMP, timeStamp, Constants.VERSION, version, signKey);
+        final String data = String.join("", jsonSign, querySign);
+        return SignUtils.sign(SignUtils.SIGN_MD5, extSignKey, data).toUpperCase();
+    }
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
index af556da5b..c0ad805ef 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/DefaultSignProvider.java
@@ -19,7 +19,10 @@ package org.apache.shenyu.plugin.sign.api;
 
 import org.apache.shenyu.common.utils.SignUtils;
 
+import java.util.Comparator;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * The Sign plugin default signer.
@@ -29,13 +32,28 @@ public class DefaultSignProvider implements SignProvider {
     /**
      * acquired sign.
      *
-     * @param signKey sign key
-     * @param jsonParams json params
-     * @param queryParams  url query params
+     * @param signKey     sign key
+     * @param jsonParams  json params
+     * @param queryParams url query params
      * @return sign
      */
     @Override
     public String generateSign(final String signKey, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
-        return SignUtils.generateSign(signKey, jsonParams, queryParams);
+
+        final String jsonSign = Optional.ofNullable(jsonParams).map(e -> e.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .map(key -> String.join("", key, jsonParams.get(key)))
+                .collect(Collectors.joining()).trim())
+                .orElse("");
+
+        final String querySign = Optional.ofNullable(queryParams).map(e -> e.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .map(key -> String.join("", key, queryParams.get(key)))
+                .collect(Collectors.joining()).trim())
+                .orElse("");
+
+        final String data = String.join("", jsonSign, querySign);
+
+        return SignUtils.sign(SignUtils.SIGN_MD5, signKey, data).toUpperCase();
     }
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/DefaultSignService.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/DefaultSignService.java
index b5297943e..11762196d 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/DefaultSignService.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/DefaultSignService.java
@@ -25,10 +25,10 @@ import org.apache.shenyu.common.dto.AppAuthData;
 import org.apache.shenyu.common.dto.AuthParamData;
 import org.apache.shenyu.common.dto.AuthPathData;
 import org.apache.shenyu.common.utils.DateUtils;
-import org.apache.shenyu.plugin.base.utils.PathMatchUtils;
-import org.apache.shenyu.common.utils.SignUtils;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.plugin.api.context.ShenyuContext;
 import org.apache.shenyu.plugin.api.result.ShenyuResultEnum;
+import org.apache.shenyu.plugin.base.utils.PathMatchUtils;
 import org.apache.shenyu.plugin.sign.api.ShenyuSignProviderWrap;
 import org.apache.shenyu.plugin.sign.api.SignService;
 import org.apache.shenyu.plugin.sign.api.VerifyResult;
@@ -151,7 +151,7 @@ public class DefaultSignService implements SignService {
                                     final Map<String, Object> requestBody,
                                     final Map<String, String> queryParams) {
 
-        final String sign = ShenyuSignProviderWrap.generateSign(buildExtSignKey(appAuthData.getAppSecret(), signParameters), SignUtils.transStringMap(requestBody), queryParams);
+        final String sign = ShenyuSignProviderWrap.generateSign(buildExtSignKey(appAuthData.getAppSecret(), signParameters), MapUtils.transStringMap(requestBody), queryParams);
         boolean result = Objects.equals(sign, signParameters.sign);
         if (!result) {
             LOG.error("the SignUtils generated signature value is:{},the accepted value is:{}", sign, signParameters.sign);
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
index e71a9dfcd..3a14af378 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
@@ -25,6 +25,7 @@ import org.apache.shenyu.common.dto.AuthParamData;
 import org.apache.shenyu.common.dto.AuthPathData;
 import org.apache.shenyu.common.dto.PluginData;
 import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.MapUtils;
 import org.apache.shenyu.common.utils.SignUtils;
 import org.apache.shenyu.plugin.api.context.ShenyuContext;
 import org.apache.shenyu.plugin.api.result.ShenyuResultEnum;
@@ -48,7 +49,10 @@ import org.springframework.mock.web.server.MockServerWebExchange;
 import org.springframework.web.server.ServerWebExchange;
 
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.Mockito.mock;
@@ -243,7 +247,7 @@ public final class DefaultSignServiceTest {
     public void bodySign() {
         Map<String, Object> requestBody = Maps.newHashMapWithExpectedSize(1);
         requestBody.put("data", "data");
-        this.passed.setSign(buildSign(this.secretKey, this.passed.getTimestamp(), this.passed.getPath(), SignUtils.transStringMap(requestBody), null));
+        this.passed.setSign(buildSign(this.secretKey, this.passed.getTimestamp(), this.passed.getPath(), MapUtils.transStringMap(requestBody), null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
         VerifyResult ret = this.signService.signVerify(this.exchange, requestBody, null);
         assertEquals(ret, VerifyResult.success());
@@ -255,7 +259,7 @@ public final class DefaultSignServiceTest {
         requestBody.put("data", "data");
         Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(1);
         queryParams.put("data2", "data");
-        this.passed.setSign(buildSign(this.secretKey, this.passed.getTimestamp(), this.passed.getPath(), SignUtils.transStringMap(requestBody), queryParams));
+        this.passed.setSign(buildSign(this.secretKey, this.passed.getTimestamp(), this.passed.getPath(), MapUtils.transStringMap(requestBody), queryParams));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
         VerifyResult ret = this.signService.signVerify(this.exchange, requestBody, queryParams);
         assertEquals(ret, VerifyResult.success());
@@ -267,7 +271,7 @@ public final class DefaultSignServiceTest {
         requestBody.put("data", "data");
         Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(1);
         queryParams.put("data", "data");
-        this.passed.setSign(buildSign(this.secretKey, this.passed.getTimestamp(), this.passed.getPath(), SignUtils.transStringMap(requestBody), null));
+        this.passed.setSign(buildSign(this.secretKey, this.passed.getTimestamp(), this.passed.getPath(), MapUtils.transStringMap(requestBody), null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
         // Tamper with request body parameters
         requestBody.put("data", "data2");
@@ -276,7 +280,21 @@ public final class DefaultSignServiceTest {
     }
 
     private String buildSign(final String signKey, final String timeStamp, final String path, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
+
+        final String jsonSign = Optional.ofNullable(jsonParams).map(e -> e.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .map(key -> String.join("", key, jsonParams.get(key)))
+                .collect(Collectors.joining()).trim())
+                .orElse("");
+
+        final String querySign = Optional.ofNullable(queryParams).map(e -> e.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .map(key -> String.join("", key, queryParams.get(key)))
+                .collect(Collectors.joining()).trim())
+                .orElse("");
+
         final String extSignKey = String.join("", Constants.PATH, path, Constants.TIMESTAMP, timeStamp, Constants.VERSION, "1.0.0", signKey);
-        return SignUtils.generateSign(extSignKey, jsonParams, queryParams);
+        final String data = String.join("", jsonSign, querySign);
+        return SignUtils.sign(SignUtils.SIGN_MD5, extSignKey, data).toUpperCase();
     }
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/sign/DefaultSignProviderTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/sign/DefaultSignProviderTest.java
index e69b2c44d..62f024f2c 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/sign/DefaultSignProviderTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/sign/DefaultSignProviderTest.java
@@ -30,7 +30,8 @@ import org.springframework.context.ConfigurableApplicationContext;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.junit.Assert.assertNotNull;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -53,8 +54,9 @@ public class DefaultSignProviderTest {
         jsonParams.put("a", "1");
         jsonParams.put("b", "2");
         Map<String, String> queryParams = new HashMap<>();
-        jsonParams.put("a", "1");
-        jsonParams.put("b", "2");
-        assertNotNull(ShenyuSignProviderWrap.generateSign("test", jsonParams, queryParams));
+        queryParams.put("a", "1");
+        queryParams.put("b", "2");
+        assertThat(ShenyuSignProviderWrap.generateSign("test", jsonParams, queryParams),
+                is("9DDBB668873D97C25904FD9D5D6314CD"));
     }
 }
diff --git a/shenyu-web/src/main/java/org/apache/shenyu/web/controller/LocalPluginController.java b/shenyu-web/src/main/java/org/apache/shenyu/web/controller/LocalPluginController.java
index 6e75463b3..5c68dcf9c 100644
--- a/shenyu-web/src/main/java/org/apache/shenyu/web/controller/LocalPluginController.java
+++ b/shenyu-web/src/main/java/org/apache/shenyu/web/controller/LocalPluginController.java
@@ -53,11 +53,11 @@ import java.util.stream.Collectors;
 @RestController
 @RequestMapping(value = "/shenyu", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
 public class LocalPluginController {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(LocalPluginController.class);
-    
+
     private final PluginDataSubscriber subscriber;
-    
+
     /**
      * Instantiates a new Plugin controller.
      *
@@ -66,7 +66,7 @@ public class LocalPluginController {
     public LocalPluginController(final PluginDataSubscriber subscriber) {
         this.subscriber = subscriber;
     }
-    
+
     /**
      * Clean all mono.
      *
@@ -80,7 +80,7 @@ public class LocalPluginController {
         subscriber.refreshRuleDataAll();
         return Mono.just(Constants.SUCCESS);
     }
-    
+
     /**
      * Clean plugin mono.
      *
@@ -101,7 +101,7 @@ public class LocalPluginController {
         }
         return Mono.just(Constants.SUCCESS);
     }
-    
+
     /**
      * Add plugin string.
      *
@@ -317,7 +317,7 @@ public class LocalPluginController {
         }
         return Mono.just(JsonUtils.toJson(ruleDataList));
     }
-    
+
     private SelectorData buildDefaultSelectorData(final SelectorData selectorData) {
         if (StringUtils.isEmpty(selectorData.getId())) {
             selectorData.setId(UUIDUtils.getInstance().generateShortUuid());
@@ -342,7 +342,7 @@ public class LocalPluginController {
         }
         return selectorData;
     }
-    
+
     private RuleData buildDefaultRuleData(final RuleData ruleData) {
         if (StringUtils.isEmpty(ruleData.getId())) {
             ruleData.setId(UUIDUtils.getInstance().generateShortUuid());
@@ -364,22 +364,22 @@ public class LocalPluginController {
         }
         return ruleData;
     }
-    
+
     /**
      * The type Selector rule data.
      */
     public static class SelectorRuleData {
-        
+
         private String pluginName;
-        
+
         private String selectorName;
-        
+
         private String selectorHandler;
-    
+
         private String ruleHandler;
-    
+
         private List<ConditionData> conditionDataList;
-    
+
         /**
          * Gets plugin name.
          *
@@ -388,7 +388,7 @@ public class LocalPluginController {
         public String getPluginName() {
             return pluginName;
         }
-    
+
         /**
          * Sets plugin name.
          *
@@ -397,7 +397,7 @@ public class LocalPluginController {
         public void setPluginName(final String pluginName) {
             this.pluginName = pluginName;
         }
-    
+
         /**
          * Gets selector name.
          *
@@ -406,7 +406,7 @@ public class LocalPluginController {
         public String getSelectorName() {
             return selectorName;
         }
-    
+
         /**
          * Sets selector name.
          *
@@ -415,7 +415,7 @@ public class LocalPluginController {
         public void setSelectorName(final String selectorName) {
             this.selectorName = selectorName;
         }
-    
+
         /**
          * Gets selector handler.
          *
@@ -424,7 +424,7 @@ public class LocalPluginController {
         public String getSelectorHandler() {
             return selectorHandler;
         }
-    
+
         /**
          * Sets selector handler.
          *
@@ -433,7 +433,7 @@ public class LocalPluginController {
         public void setSelectorHandler(final String selectorHandler) {
             this.selectorHandler = selectorHandler;
         }
-    
+
         /**
          * Gets rule handler.
          *
@@ -442,7 +442,7 @@ public class LocalPluginController {
         public String getRuleHandler() {
             return ruleHandler;
         }
-    
+
         /**
          * Sets rule handler.
          *
@@ -451,7 +451,7 @@ public class LocalPluginController {
         public void setRuleHandler(final String ruleHandler) {
             this.ruleHandler = ruleHandler;
         }
-    
+
         /**
          * Gets condition data list.
          *
@@ -460,7 +460,7 @@ public class LocalPluginController {
         public List<ConditionData> getConditionDataList() {
             return conditionDataList;
         }
-    
+
         /**
          * Sets condition data list.
          *
@@ -470,24 +470,24 @@ public class LocalPluginController {
             this.conditionDataList = conditionDataList;
         }
     }
-    
+
     /**
      * The type Selector rules data.
      */
     public static class SelectorRulesData {
-        
+
         private String pluginName;
-    
+
         private String selectorName;
-    
+
         private Integer matchMode;
-    
+
         private String selectorHandler;
-    
+
         private List<ConditionData> conditionDataList;
-    
+
         private List<RuleLocalData> ruleDataList;
-    
+
         /**
          * Gets plugin name.
          *
@@ -496,7 +496,7 @@ public class LocalPluginController {
         public String getPluginName() {
             return pluginName;
         }
-    
+
         /**
          * Sets plugin name.
          *
@@ -505,7 +505,7 @@ public class LocalPluginController {
         public void setPluginName(final String pluginName) {
             this.pluginName = pluginName;
         }
-    
+
         /**
          * Gets selector name.
          *
@@ -514,7 +514,7 @@ public class LocalPluginController {
         public String getSelectorName() {
             return selectorName;
         }
-    
+
         /**
          * Sets selector name.
          *
@@ -523,7 +523,7 @@ public class LocalPluginController {
         public void setSelectorName(final String selectorName) {
             this.selectorName = selectorName;
         }
-    
+
         /**
          * Gets selector handler.
          *
@@ -532,7 +532,7 @@ public class LocalPluginController {
         public String getSelectorHandler() {
             return selectorHandler;
         }
-    
+
         /**
          * Sets selector handler.
          *
@@ -541,7 +541,7 @@ public class LocalPluginController {
         public void setSelectorHandler(final String selectorHandler) {
             this.selectorHandler = selectorHandler;
         }
-    
+
         /**
          * Gets match mode.
          *
@@ -550,7 +550,7 @@ public class LocalPluginController {
         public Integer getMatchMode() {
             return matchMode;
         }
-    
+
         /**
          * Sets match mode.
          *
@@ -559,7 +559,7 @@ public class LocalPluginController {
         public void setMatchMode(final Integer matchMode) {
             this.matchMode = matchMode;
         }
-    
+
         /**
          * Gets condition data list.
          *
@@ -568,7 +568,7 @@ public class LocalPluginController {
         public List<ConditionData> getConditionDataList() {
             return conditionDataList;
         }
-    
+
         /**
          * Sets condition data list.
          *
@@ -577,7 +577,7 @@ public class LocalPluginController {
         public void setConditionDataList(final List<ConditionData> conditionDataList) {
             this.conditionDataList = conditionDataList;
         }
-    
+
         /**
          * Gets rule data list.
          *
@@ -586,7 +586,7 @@ public class LocalPluginController {
         public List<RuleLocalData> getRuleDataList() {
             return ruleDataList;
         }
-    
+
         /**
          * Sets rule data list.
          *
@@ -595,22 +595,22 @@ public class LocalPluginController {
         public void setRuleDataList(final List<RuleLocalData> ruleDataList) {
             this.ruleDataList = ruleDataList;
         }
-        
+
     }
-    
+
     /**
      * The type Rule data dto.
      */
     public static class RuleLocalData {
-    
+
         private String ruleName;
-        
+
         private String ruleHandler;
-        
+
         private Integer matchMode;
-        
+
         private List<ConditionData> conditionDataList;
-    
+
         /**
          * Gets rule name.
          *
@@ -619,7 +619,7 @@ public class LocalPluginController {
         public String getRuleName() {
             return ruleName;
         }
-    
+
         /**
          * Sets rule name.
          *
@@ -628,7 +628,7 @@ public class LocalPluginController {
         public void setRuleName(final String ruleName) {
             this.ruleName = ruleName;
         }
-    
+
         /**
          * Gets rule handler.
          *
@@ -637,7 +637,7 @@ public class LocalPluginController {
         public String getRuleHandler() {
             return ruleHandler;
         }
-    
+
         /**
          * Sets rule handler.
          *
@@ -646,7 +646,7 @@ public class LocalPluginController {
         public void setRuleHandler(final String ruleHandler) {
             this.ruleHandler = ruleHandler;
         }
-    
+
         /**
          * Gets match mode.
          *
@@ -655,7 +655,7 @@ public class LocalPluginController {
         public Integer getMatchMode() {
             return matchMode;
         }
-    
+
         /**
          * Sets match mode.
          *
@@ -664,7 +664,7 @@ public class LocalPluginController {
         public void setMatchMode(final Integer matchMode) {
             this.matchMode = matchMode;
         }
-    
+
         /**
          * Gets condition data list.
          *
@@ -673,7 +673,7 @@ public class LocalPluginController {
         public List<ConditionData> getConditionDataList() {
             return conditionDataList;
         }
-    
+
         /**
          * Sets condition data list.
          *