You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2023/01/16 06:37:18 UTC

[shenyu] branch master updated: Fixed compatibility of Sign-Plugin of 2.5.0 version (#4316)

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

xiaoyu 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 c1408e545 Fixed compatibility of Sign-Plugin of  2.5.0 version (#4316)
c1408e545 is described below

commit c1408e545f4333f38156ffcbe50acf63b4936ff8
Author: 愿凌飞 <ti...@foxmail.com>
AuthorDate: Mon Jan 16 14:37:12 2023 +0800

    Fixed compatibility of Sign-Plugin of  2.5.0 version (#4316)
    
    * [ISSUE #4208] Refactored Sign-plugin
    
    * fix
    
    * fix
    
    * fix
    
    * fix code style
    
    * fix
    
    * fix
    
    * added versionOne and VersionTwo
    
    * code style
    
    * fix
    
    * fix
    
    * fix
    
    * fix
    
    * code style
    
    * code style
    
    Co-authored-by: xiaoyu <xi...@apache.org>
---
 .../http/combination/SignPluginVersionOneTest.java | 289 +++++++++++++++++++++
 ...uginTest.java => SignPluginVersionTwoTest.java} |  35 ++-
 .../shenyu/plugin/sign/api/SignParameters.java     |  23 +-
 .../plugin/sign/extractor/DefaultExtractor.java    |  40 +--
 ...aultExtractor.java => VersionOneExtractor.java} |  34 +--
 ...aultExtractor.java => VersionTwoExtractor.java} |   5 +-
 .../plugin/sign/provider/DefaultSignProvider.java  |  36 ++-
 .../sign/provider/VersionOneSignProvider.java      |  85 ++++++
 ...gnProvider.java => VersionTwoSignProvider.java} |   8 +-
 .../plugin/sign/service/ComposableSignService.java |   3 +-
 .../sign/extractor/DefaultExtractorTest.java       |  24 +-
 .../sign/provider/DefaultSignProviderTest.java     |  13 +-
 ...iceTest.java => SignServiceVersionOneTest.java} | 162 ++++++------
 ...iceTest.java => SignServiceVersionTwoTest.java} |   7 +-
 14 files changed, 570 insertions(+), 194 deletions(-)

diff --git a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionOneTest.java b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionOneTest.java
new file mode 100644
index 000000000..fca030a9e
--- /dev/null
+++ b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionOneTest.java
@@ -0,0 +1,289 @@
+/*
+ * 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.integrated.test.http.combination;
+
+import com.google.common.collect.Maps;
+import com.google.gson.reflect.TypeToken;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.dto.AuthParamData;
+import org.apache.shenyu.common.dto.AuthPathData;
+import org.apache.shenyu.common.dto.ConditionData;
+import org.apache.shenyu.common.enums.OperatorEnum;
+import org.apache.shenyu.common.enums.ParamTypeEnum;
+import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.DigestUtils;
+import org.apache.shenyu.integratedtest.common.AbstractPluginDataInit;
+import org.apache.shenyu.integratedtest.common.dto.AdminResponse;
+import org.apache.shenyu.integratedtest.common.dto.UserDTO;
+import org.apache.shenyu.integratedtest.common.helper.HttpHelper;
+import org.apache.shenyu.web.controller.LocalPluginController.RuleLocalData;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static org.apache.shenyu.common.constant.Constants.SIGN_PARAMS_ERROR;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public final class SignPluginVersionOneTest extends AbstractPluginDataInit {
+
+    private static final String APP_KEY = "108C27175A2C43C1BC29B1E483D57E3D";
+
+    private static final String APP_SECRET = "061521A73DD94A3FA873C25D050685BB";
+
+    @Test
+    public void testSign() throws Exception {
+        String authResult = initAuthData(APP_KEY, APP_SECRET, buildAuthParamDataList(), buildAuthPathDataList());
+        assertThat(authResult, is("success"));
+        String pluginResult = initPlugin(PluginEnum.SIGN.getName(), null);
+        assertThat(pluginResult, is("success"));
+        String selectorAndRulesResult = initSelectorAndRules(PluginEnum.SIGN.getName(), "", buildSelectorConditionList(), buildRuleLocalDataList());
+        assertThat(selectorAndRulesResult, is("success"));
+        final String path = "/http/test/path/456";
+        final String testUrlPath = "/http/test/path/456?name=Lee&data=3";
+        final String version = "1.0.0";
+        String now = String.valueOf(System.currentTimeMillis());
+        Map<String, Object> normalHeaders = buildHeadersMap(now, path, APP_KEY, APP_SECRET, version);
+        UserDTO normalRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath, normalHeaders,
+                UserDTO.class);
+        assertEquals("Lee", normalRespFuture.getUserName());
+
+        Map<String, Object> errorPathHeaders = buildHeadersMap(now, "errorPath", APP_KEY, APP_SECRET, version);
+        AdminResponse<Object> rejectedErrorPathRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorPathHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("signature value is error!", rejectedErrorPathRespFuture.getMessage());
+
+        Map<String, Object> errorAppKeyHeaders = buildHeadersMap(now, path, "ERRORKEY", APP_SECRET, version);
+        AdminResponse<Object> rejectedErrorAKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorAppKeyHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("sign appKey does not exist.", rejectedErrorAKRespFuture.getMessage());
+
+        Map<String, Object> errorAppSecretHeaders = buildHeadersMap(now, path, APP_KEY, "ERRORSECRET", version);
+        AdminResponse<Object> rejectedErrorSKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorAppSecretHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("signature value is error!", rejectedErrorSKRespFuture.getMessage());
+
+        Map<String, Object> errorVersionHeaders = buildHeadersMap(now, path, APP_KEY, APP_SECRET, "1.0.2");
+        AdminResponse<Object> rejectedErrorVersionRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorVersionHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals(SIGN_PARAMS_ERROR, rejectedErrorVersionRespFuture.getMessage());
+
+        String errorTime = String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+0")).toEpochMilli() - 360000);
+        Map<String, Object> errorTimestampHeaders = buildHeadersMap(errorTime, path, APP_KEY, APP_SECRET, version);
+        AdminResponse<Object> rejectedErrorTimestampRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorTimestampHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("The signature timestamp has exceeded 5 minutes!", rejectedErrorTimestampRespFuture.getMessage());
+    }
+
+    @Test
+    public void testSignRequestBody() throws Exception {
+
+        String authResult = initAuthData(APP_KEY, APP_SECRET, buildAuthParamDataList(), buildAuthPathDataList());
+        assertThat(authResult, is("success"));
+        String pluginResult = initPlugin(PluginEnum.SIGN.getName(), null);
+        assertThat(pluginResult, is("success"));
+        String selectorAndRulesResult = initSelectorAndRules(PluginEnum.SIGN.getName(), "",
+                buildSelectorConditionListOpenRequestBody(), buildRuleLocalDataListRequestBody());
+        assertThat(selectorAndRulesResult, is("success"));
+        final String path = "/http/test/path/789";
+        final String testUrlPath = "/http/test/path/789?name=Lee&data=3";
+        final String version = "1.0.0";
+        String now = String.valueOf(System.currentTimeMillis());
+        Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(2);
+        requestBody.put("name", "Lee");
+        requestBody.put("data", "3");
+        Map<String, Object> normalHeaders = buildHeadersMapRequestBody(now, path, APP_KEY, APP_SECRET, version, requestBody);
+        UserDTO normalRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath, normalHeaders,
+                UserDTO.class);
+        assertEquals("Lee", normalRespFuture.getUserName());
+
+        Map<String, Object> errorPathHeaders = buildHeadersMapRequestBody(now, "errorPath", APP_KEY, APP_SECRET, version, requestBody);
+        AdminResponse<Object> rejectedErrorPathRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorPathHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("signature value is error!", rejectedErrorPathRespFuture.getMessage());
+
+        Map<String, Object> errorAppKeyHeaders = buildHeadersMapRequestBody(now, path, "ERRORKEY", APP_SECRET, version, requestBody);
+        AdminResponse<Object> rejectedErrorAKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorAppKeyHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("sign appKey does not exist.", rejectedErrorAKRespFuture.getMessage());
+
+        Map<String, Object> errorAppSecretHeaders = buildHeadersMapRequestBody(now, path, APP_KEY, "ERRORSECRET", version, requestBody);
+        AdminResponse<Object> rejectedErrorSKRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorAppSecretHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("signature value is error!", rejectedErrorSKRespFuture.getMessage());
+
+        Map<String, Object> errorVersionHeaders = buildHeadersMapRequestBody(now, path, APP_KEY, APP_SECRET, "1.0.2", requestBody);
+        AdminResponse<Object> rejectedErrorVersionRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorVersionHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals(SIGN_PARAMS_ERROR, rejectedErrorVersionRespFuture.getMessage());
+
+        Map<String, Object> errorRequestBody = buildHeadersMapRequestBody(now, path, APP_KEY, APP_SECRET, "1.0.0", null);
+        AdminResponse<Object> rejectedErrorRequestBodyRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorRequestBody,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("signature value is error!", rejectedErrorRequestBodyRespFuture.getMessage());
+
+        String errorTime = String.valueOf(System.currentTimeMillis() - 360000);
+        Map<String, Object> errorTimestampHeaders = buildHeadersMapRequestBody(errorTime, path, APP_KEY, APP_SECRET, version, requestBody);
+        AdminResponse<Object> rejectedErrorTimestampRespFuture = HttpHelper.INSTANCE.getFromGateway(testUrlPath,
+                errorTimestampHeaders,
+                new TypeToken<AdminResponse<Object>>() {
+                }.getType());
+        assertEquals("The signature timestamp has exceeded 5 minutes!", rejectedErrorTimestampRespFuture.getMessage());
+    }
+
+    private Map<String, Object> buildHeadersMap(final String timestamp, final String path, final String appKey,
+                                                final String appSecret, final String version) {
+        Map<String, String> params = Maps.newHashMapWithExpectedSize(3);
+        params.put("timestamp", timestamp);
+        params.put("path", path);
+        params.put("version", version);
+        String sign = generateSign(appSecret, params);
+
+        Map<String, Object> headers = Maps.newHashMapWithExpectedSize(4);
+        headers.put("timestamp", timestamp);
+        headers.put("appKey", appKey);
+        headers.put("sign", sign);
+        headers.put("version", version);
+        return headers;
+    }
+
+    private Map<String, Object> buildHeadersMapRequestBody(final String timestamp, final String path, final String appKey,
+                                                           final String appSecret, final String version, final Map<String, String> requestBody) {
+        Map<String, String> params = Maps.newHashMapWithExpectedSize(3);
+        params.put("timestamp", timestamp);
+        params.put("path", path);
+        params.put("version", version);
+        if (!ObjectUtils.isEmpty(requestBody)) {
+            params.putAll(requestBody);
+        }
+        String sign = generateSign(appSecret, params);
+
+        Map<String, Object> headers = Maps.newHashMapWithExpectedSize(4);
+        headers.put("timestamp", timestamp);
+        headers.put("appKey", appKey);
+        headers.put("sign", sign);
+        headers.put("version", version);
+        return headers;
+    }
+
+    private static List<AuthParamData> buildAuthParamDataList() {
+        AuthParamData authParamData = new AuthParamData();
+        authParamData.setAppName("http-sign");
+        authParamData.setAppParam("appParam");
+        return Collections.singletonList(authParamData);
+    }
+
+    private static List<AuthPathData> buildAuthPathDataList() {
+        AuthPathData authPathData = new AuthPathData();
+        authPathData.setAppName("http-sign");
+        authPathData.setPath("/http/test/path/456");
+        authPathData.setEnabled(true);
+        AuthPathData authPathData2 = new AuthPathData();
+        authPathData2.setAppName("http-sign");
+        authPathData2.setPath("/http/test/path/789");
+        authPathData2.setEnabled(true);
+        return Arrays.asList(authPathData, authPathData2);
+    }
+
+    private static List<ConditionData> buildSelectorConditionList() {
+        ConditionData conditionData = new ConditionData();
+        conditionData.setParamType(ParamTypeEnum.URI.getName());
+        conditionData.setOperator(OperatorEnum.EQ.getAlias());
+        conditionData.setParamValue("/http/test/path/456");
+        return Collections.singletonList(conditionData);
+    }
+
+    private static List<ConditionData> buildSelectorConditionListOpenRequestBody() {
+        ConditionData conditionData2 = new ConditionData();
+        conditionData2.setParamType(ParamTypeEnum.URI.getName());
+        conditionData2.setOperator(OperatorEnum.EQ.getAlias());
+        conditionData2.setParamValue("/http/test/path/789");
+        return Collections.singletonList(conditionData2);
+    }
+
+    private static List<RuleLocalData> buildRuleLocalDataList() {
+        final RuleLocalData ruleLocalData = new RuleLocalData();
+        ConditionData conditionData = new ConditionData();
+        conditionData.setParamType(ParamTypeEnum.URI.getName());
+        conditionData.setOperator(OperatorEnum.EQ.getAlias());
+        conditionData.setParamValue("/http/test/path/456");
+        ruleLocalData.setConditionDataList(Collections.singletonList(conditionData));
+        ruleLocalData.setRuleHandler("{\"signRequestBody\": false}");
+        return Collections.singletonList(ruleLocalData);
+    }
+
+    private static List<RuleLocalData> buildRuleLocalDataListRequestBody() {
+        final RuleLocalData ruleLocalData2 = new RuleLocalData();
+        ConditionData conditionData2 = new ConditionData();
+        conditionData2.setParamType(ParamTypeEnum.URI.getName());
+        conditionData2.setOperator(OperatorEnum.EQ.getAlias());
+        conditionData2.setParamValue("/http/test/path/789");
+        ruleLocalData2.setConditionDataList(Collections.singletonList(conditionData2));
+        ruleLocalData2.setRuleHandler("{\"signRequestBody\": true}");
+        return Collections.singletonList(ruleLocalData2);
+    }
+
+    @AfterAll
+    public static void clean() throws IOException {
+        cleanPluginData(PluginEnum.SIGN.getName());
+        cleanAuthData(APP_KEY);
+    }
+
+    private String generateSign(final String signKey, final Map<String, String> params) {
+        final String sign = params.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .filter(key -> !Objects.equals(key, Constants.SIGN))
+                .map(key -> String.join("", key, params.get(key)))
+                .collect(Collectors.joining()).trim()
+                .concat(signKey);
+        // TODO this is a risk for error charset coding with getBytes
+        return DigestUtils.md5Hex(sign.getBytes()).toUpperCase();
+    }
+}
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/SignPluginVersionTwoTest.java
similarity index 90%
rename from shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginTest.java
rename to shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SignPluginVersionTwoTest.java
index 86890fdbe..00bcaa1c5 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/SignPluginVersionTwoTest.java
@@ -51,9 +51,10 @@ import java.util.Objects;
 import java.util.Optional;
 
 import static org.apache.shenyu.integratedtest.common.helper.HttpHelper.GATEWAY_END_POINT;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public final class SignPluginTest extends AbstractPluginDataInit {
+public final class SignPluginVersionTwoTest extends AbstractPluginDataInit {
 
     private static final String APP_KEY = "108C27175A2C43C1BC29B1E483D57E3D";
 
@@ -67,8 +68,6 @@ public final class SignPluginTest extends AbstractPluginDataInit {
 
     private static final String POST_URL = "/http/test/payment?userName=Lee&userId=3";
 
-    private static final String VERSION = "1.0.0";
-
     @BeforeAll
     public static void setUp() throws IOException {
         initAuthData(APP_KEY, APP_SECRET, buildAuthParamDataList(), buildAuthPathDataList());
@@ -80,7 +79,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
     @Test
     public void testSign() throws Exception {
         String now = String.valueOf(System.currentTimeMillis());
-        Map<String, Object> normalHeaders = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, APP_KEY, APP_SECRET, VERSION, null);
+        Map<String, Object> normalHeaders = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, APP_KEY, APP_SECRET, null);
         UserDTO result = HttpHelper.INSTANCE
                 .getFromGateway(GET_URL, normalHeaders, UserDTO.class);
         assertEquals("Lee", result.getUserName());
@@ -89,7 +88,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
     @Test
     public void testSignWithWrongPath() throws Exception {
         String now = String.valueOf(System.currentTimeMillis());
-        Map<String, Object> errorPathHeaders = buildHeadersMap(GATEWAY_END_POINT + "/wrong_path", now, APP_KEY, APP_SECRET, VERSION, null);
+        Map<String, Object> errorPathHeaders = buildHeadersMap(GATEWAY_END_POINT + "/wrong_path", now, APP_KEY, APP_SECRET, null);
         AdminResponse<Object> result = HttpHelper.INSTANCE
                 .getFromGateway(GET_URL, errorPathHeaders, AdminResponse.class);
         assertEquals("signature value is error!", result.getMessage());
@@ -98,7 +97,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
     @Test
     public void testSignWithWrongKey() throws Exception {
         String now = String.valueOf(System.currentTimeMillis());
-        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, "ERRORKEY", APP_SECRET, VERSION, null);
+        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, now, "ERRORKEY", APP_SECRET, null);
 
         AdminResponse<Object> result = HttpHelper.INSTANCE
                 .getFromGateway(GET_URL, headers, AdminResponse.class);
@@ -110,7 +109,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
     public void testSignWithExpiredSignature() throws Exception {
 
         String errorTime = String.valueOf(System.currentTimeMillis() - 360000);
-        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, errorTime, APP_KEY, APP_SECRET, VERSION, null);
+        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + GET_URL, errorTime, APP_KEY, APP_SECRET, null);
 
         AdminResponse<Object> result = HttpHelper.INSTANCE
                 .getFromGateway(GET_URL, headers, AdminResponse.class);
@@ -125,7 +124,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
         Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(2);
         requestBody.put("userName", "Lee");
         requestBody.put("userId", "3");
-        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, VERSION, JsonUtils.toJson(requestBody));
+        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, JsonUtils.toJson(requestBody));
 
         UserDTO result = HttpHelper.INSTANCE
                 .postGateway(POST_URL, headers, requestBody, UserDTO.class);
@@ -142,7 +141,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
         requestBody.put("userName", "Lee");
         requestBody.put("userId", "3");
 
-        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, VERSION, JsonUtils.toJson(ImmutableMap.of("userId", "1234")));
+        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL, now, APP_KEY, APP_SECRET, JsonUtils.toJson(ImmutableMap.of("userId", "1234")));
         AdminResponse<Object> result = HttpHelper.INSTANCE
                 .postGateway(POST_URL, headers, requestBody, AdminResponse.class);
 
@@ -152,8 +151,11 @@ public final class SignPluginTest extends AbstractPluginDataInit {
     @Test
     public void testSignWithIncompleteParam() throws Exception {
 
+        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + POST_URL,
+                null, APP_KEY, APP_SECRET, null);
+
         AdminResponse<Object> result = HttpHelper.INSTANCE
-                .getFromGateway(GET_URL, AdminResponse.class);
+                .getFromGateway(GET_URL, headers, AdminResponse.class);
 
         assertEquals("sign parameters are incomplete!", result.getMessage());
     }
@@ -167,7 +169,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
                 buildSelectorConditionList(notConfiguredPath),
                 buildRuleLocalDataList(false, notConfiguredPath));
         String now = String.valueOf(System.currentTimeMillis());
-        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + notConfiguredPath, now, APP_KEY, APP_SECRET, "1.0.0", null);
+        Map<String, Object> headers = buildHeadersMap(GATEWAY_END_POINT + notConfiguredPath, now, APP_KEY, APP_SECRET, null);
 
         AdminResponse<Object> result = HttpHelper.INSTANCE
                 .getFromGateway(notConfiguredPath, headers, AdminResponse.class);
@@ -178,11 +180,11 @@ public final class SignPluginTest extends AbstractPluginDataInit {
 
     @Test
     private Map<String, Object> buildHeadersMap(final String uri, final String timestamp, final String appKey,
-                                                final String appSecret, final String version, final String requestBody) {
-        String parameters = buildParameters(timestamp, appKey, version);
+                                                final String appSecret, final String requestBody) {
+        String parameters = buildParameters(timestamp, appKey);
         String sign = buildSign(appSecret, parameters, URI.create(uri), requestBody);
         String token = parameters + "." + sign;
-        return ImmutableMap.of(HttpHeaders.AUTHORIZATION, token);
+        return ImmutableMap.of(HttpHeaders.AUTHORIZATION, token, Constants.VERSION, VERSION_2);
     }
 
     private static List<AuthParamData> buildAuthParamDataList() {
@@ -227,7 +229,7 @@ public final class SignPluginTest extends AbstractPluginDataInit {
         cleanAuthData(APP_KEY);
     }
 
-    private String buildParameters(final String timestamp, final String appKey, final String version) {
+    private String buildParameters(final String timestamp, final String appKey) {
         Map<String, String> map = new HashMap<>();
         if (timestamp != null) {
             map.put(Constants.TIMESTAMP, timestamp);
@@ -235,9 +237,6 @@ public final class SignPluginTest extends AbstractPluginDataInit {
         if (appKey != null) {
             map.put(Constants.APP_KEY, appKey);
         }
-        if (version != null) {
-            map.put("version", version);
-        }
         map.put("alg", "MD5");
         return Base64.getEncoder().encodeToString(JsonUtils.toJson(map).getBytes(StandardCharsets.UTF_8));
     }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java
index 3cb57cdfa..180cf8ab2 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/api/SignParameters.java
@@ -23,6 +23,8 @@ import java.net.URI;
 
 public class SignParameters {
 
+    public static final SignParameters ERROR_PARAMETERS = new SignParameters();
+
     private final String appKey;
 
     private final String timestamp;
@@ -33,20 +35,25 @@ public class SignParameters {
 
     private final String signAlg;
 
+    private final String version;
+
     private String parameters;
 
-    public SignParameters(final String appKey,
+    public SignParameters(final String version,
+                          final String appKey,
                           final String timestamp,
                           final String signature,
                           final URI uri) {
-        this(appKey, timestamp, signature, uri, SignUtils.SIGN_MD5);
+        this(version, appKey, timestamp, signature, uri, SignUtils.SIGN_MD5);
     }
 
-    public SignParameters(final String appKey,
+    public SignParameters(final String version,
+                          final String appKey,
                           final String timestamp,
                           final String signature,
                           final URI uri,
                           final String signAlg) {
+        this.version = version;
         this.appKey = appKey;
         this.timestamp = timestamp;
         this.signature = signature;
@@ -121,6 +128,15 @@ public class SignParameters {
         this.parameters = parameters;
     }
 
+    /**
+     * Gets version.
+     *
+     * @return version
+     */
+    public String getVersion() {
+        return version;
+    }
+
     @Override
     public String toString() {
         return "SignParameters{"
@@ -129,6 +145,7 @@ public class SignParameters {
                 + ", signature='" + signature + '\''
                 + ", uri=" + uri
                 + ", signAlg='" + signAlg + '\''
+                + ", version='" + version + '\''
                 + ", parameters='" + parameters + '\''
                 + '}';
     }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
index 4d41917e4..4f380484c 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
@@ -17,40 +17,40 @@
 
 package org.apache.shenyu.plugin.sign.extractor;
 
-import org.apache.commons.lang3.StringUtils;
+import com.google.common.collect.ImmutableMap;
 import org.apache.shenyu.common.constant.Constants;
-import org.apache.shenyu.common.utils.JsonUtils;
 import org.apache.shenyu.plugin.sign.api.SignParameters;
-import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpRequest;
 
-import java.util.Base64;
 import java.util.Map;
+import java.util.Objects;
 
 public class DefaultExtractor implements SignParameterExtractor {
 
+    public static final String VERSION_1 = "1.0.0";
+
+    public static final String VERSION_2 = "2.0.0";
+
+    private static final Map<String, SignParameterExtractor> VERSION_EXTRACTOR =
+            ImmutableMap.of(
+                    VERSION_1, new VersionOneExtractor(),
+                    VERSION_2, new VersionTwoExtractor()
+            );
+
     @Override
     public SignParameters extract(final HttpRequest httpRequest) {
 
-        String token = httpRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
-
-        if (StringUtils.isEmpty(token) || !token.contains(".")) {
-            return new SignParameters();
+        String version = httpRequest.getHeaders().getFirst(Constants.VERSION);
+        if (Objects.isNull(version)) {
+            return SignParameters.ERROR_PARAMETERS;
         }
-        String[] tokenArray = StringUtils.split(token, '.');
-        String parameters = tokenArray[0];
-        String signature = tokenArray[1];
 
-        Map<String, Object> headerMap = JsonUtils.jsonToMap(new String(Base64.getDecoder().decode(parameters)));
+        SignParameterExtractor extractor = VERSION_EXTRACTOR.get(version);
 
-        SignParameters signParameters = new SignParameters(
-                (String) headerMap.get(Constants.APP_KEY),
-                (String) headerMap.get(Constants.TIMESTAMP),
-                signature,
-                httpRequest.getURI(),
-                (String) headerMap.get("alg"));
-        signParameters.setParameters(parameters);
+        if (Objects.isNull(extractor)) {
+            return SignParameters.ERROR_PARAMETERS;
+        }
 
-        return signParameters;
+        return extractor.extract(httpRequest);
     }
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractor.java
similarity index 50%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
copy to shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractor.java
index 4d41917e4..bac784987 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionOneExtractor.java
@@ -17,40 +17,22 @@
 
 package org.apache.shenyu.plugin.sign.extractor;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.shenyu.common.constant.Constants;
-import org.apache.shenyu.common.utils.JsonUtils;
 import org.apache.shenyu.plugin.sign.api.SignParameters;
-import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpRequest;
 
-import java.util.Base64;
-import java.util.Map;
+import java.net.URI;
 
-public class DefaultExtractor implements SignParameterExtractor {
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
 
+public class VersionOneExtractor implements SignParameterExtractor {
     @Override
     public SignParameters extract(final HttpRequest httpRequest) {
+        String appKey = httpRequest.getHeaders().getFirst(Constants.APP_KEY);
+        String signature = httpRequest.getHeaders().getFirst(Constants.SIGN);
+        String timestamp = httpRequest.getHeaders().getFirst(Constants.TIMESTAMP);
+        URI uri = httpRequest.getURI();
 
-        String token = httpRequest.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
-
-        if (StringUtils.isEmpty(token) || !token.contains(".")) {
-            return new SignParameters();
-        }
-        String[] tokenArray = StringUtils.split(token, '.');
-        String parameters = tokenArray[0];
-        String signature = tokenArray[1];
-
-        Map<String, Object> headerMap = JsonUtils.jsonToMap(new String(Base64.getDecoder().decode(parameters)));
-
-        SignParameters signParameters = new SignParameters(
-                (String) headerMap.get(Constants.APP_KEY),
-                (String) headerMap.get(Constants.TIMESTAMP),
-                signature,
-                httpRequest.getURI(),
-                (String) headerMap.get("alg"));
-        signParameters.setParameters(parameters);
-
-        return signParameters;
+        return new SignParameters(VERSION_1, appKey, timestamp, signature, uri);
     }
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractor.java
similarity index 92%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
copy to shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractor.java
index 4d41917e4..5e3f4b151 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractor.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/extractor/VersionTwoExtractor.java
@@ -27,7 +27,9 @@ import org.springframework.http.HttpRequest;
 import java.util.Base64;
 import java.util.Map;
 
-public class DefaultExtractor implements SignParameterExtractor {
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
+
+public class VersionTwoExtractor implements SignParameterExtractor {
 
     @Override
     public SignParameters extract(final HttpRequest httpRequest) {
@@ -44,6 +46,7 @@ public class DefaultExtractor implements SignParameterExtractor {
         Map<String, Object> headerMap = JsonUtils.jsonToMap(new String(Base64.getDecoder().decode(parameters)));
 
         SignParameters signParameters = new SignParameters(
+                VERSION_2,
                 (String) headerMap.get(Constants.APP_KEY),
                 (String) headerMap.get(Constants.TIMESTAMP),
                 signature,
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
index 413c68119..d370349a1 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
@@ -17,37 +17,31 @@
 
 package org.apache.shenyu.plugin.sign.provider;
 
-import org.apache.shenyu.common.utils.SignUtils;
+import com.google.common.collect.ImmutableMap;
 import org.apache.shenyu.plugin.sign.api.SignParameters;
 
-import java.net.URI;
-import java.util.Objects;
-import java.util.Optional;
+import java.util.Map;
+
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
 
 public class DefaultSignProvider implements SignProvider {
 
+    private static final Map<String, SignProvider> VERSION_SIGN =
+            ImmutableMap.of(
+                    VERSION_1, new VersionOneSignProvider(),
+                    VERSION_2, new VersionTwoSignProvider()
+            );
+
     @Override
     public String generateSign(final String signKey, final SignParameters signParameters, final String requestBody) {
-
-        String data = signParameters.getParameters()
-                + getRelativeURL(signParameters.getUri())
-                + Optional.ofNullable(requestBody).orElse("");
-        return SignUtils.sign(signParameters.getSignAlg(), signKey, data).toUpperCase();
+        return VERSION_SIGN.get(signParameters.getVersion())
+                .generateSign(signKey, signParameters, requestBody);
     }
 
     @Override
     public String generateSign(final String signKey, final SignParameters signParameters) {
-        return generateSign(signKey, signParameters, null);
-    }
-
-    /** Gets RelativeURL.
-     * @param uri uri
-     * @return relativeURL
-     */
-    public String getRelativeURL(final URI uri) {
-        if (Objects.isNull(uri.getQuery())) {
-            return uri.getPath();
-        }
-        return uri.getPath() + "?" + uri.getQuery();
+        return VERSION_SIGN.get(signParameters.getVersion())
+                .generateSign(signKey, signParameters);
     }
 }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProvider.java
new file mode 100644
index 000000000..45878db75
--- /dev/null
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionOneSignProvider.java
@@ -0,0 +1,85 @@
+/*
+ * 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.plugin.sign.provider;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.utils.JsonUtils;
+import org.apache.shenyu.common.utils.SignUtils;
+import org.apache.shenyu.plugin.sign.api.SignParameters;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class VersionOneSignProvider implements SignProvider {
+
+    @Override
+    public String generateSign(final String signKey, final SignParameters signParameters, final String requestBody) {
+        return sign(signKey, signParameters, requestBody);
+    }
+
+    @Override
+    public String generateSign(final String signKey, final SignParameters signParameters) {
+
+        return sign(signKey, signParameters, null);
+    }
+
+    private String sign(final String signKey, final SignParameters signParameters, final String requestBody) {
+
+        Map<String, String> params = getParams(signParameters, requestBody);
+
+        final String data = params.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .filter(key -> !Objects.equals(key, Constants.SIGN))
+                .map(key -> String.join("", key, params.get(key)))
+                .collect(Collectors.joining()).trim();
+
+        return SignUtils.sign(signParameters.getSignAlg(), signKey, data).toUpperCase();
+    }
+
+    private Map<String, String> getParams(final SignParameters signParameters, final String requestBody) {
+
+        Map<String, String> params = Maps.newHashMap();
+        params.put(Constants.TIMESTAMP, signParameters.getTimestamp());
+        params.put(Constants.PATH, signParameters.getUri().getPath());
+        params.put(Constants.VERSION, signParameters.getVersion());
+
+        if (Objects.isNull(requestBody)) {
+            return params;
+        }
+
+        //get requestBodyParameter
+        if (!StringUtils.isEmpty(requestBody)) {
+            JsonUtils.jsonToMap(requestBody)
+                    .forEach((k, v) -> params.putIfAbsent(k, Objects.toString(v, null)));
+        }
+
+        // get url params
+        Map<String, String> queryParams = UriComponentsBuilder.fromUri(signParameters.getUri())
+                .build()
+                .getQueryParams()
+                .toSingleValueMap();
+        params.putAll(queryParams);
+
+        return params;
+    }
+}
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProvider.java
similarity index 90%
copy from shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
copy to shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProvider.java
index 413c68119..6c5aded45 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProvider.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/provider/VersionTwoSignProvider.java
@@ -24,7 +24,7 @@ import java.net.URI;
 import java.util.Objects;
 import java.util.Optional;
 
-public class DefaultSignProvider implements SignProvider {
+public class VersionTwoSignProvider implements SignProvider {
 
     @Override
     public String generateSign(final String signKey, final SignParameters signParameters, final String requestBody) {
@@ -40,11 +40,7 @@ public class DefaultSignProvider implements SignProvider {
         return generateSign(signKey, signParameters, null);
     }
 
-    /** Gets RelativeURL.
-     * @param uri uri
-     * @return relativeURL
-     */
-    public String getRelativeURL(final URI uri) {
+    private String getRelativeURL(final URI uri) {
         if (Objects.isNull(uri.getQuery())) {
             return uri.getPath();
         }
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
index bed5e2616..fd9f6506a 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/main/java/org/apache/shenyu/plugin/sign/service/ComposableSignService.java
@@ -49,7 +49,8 @@ import java.util.function.BiFunction;
  * The ComposableSignService is composable SignService.
  * <pre>
  *  1. new ComposableSignService(new DefaultExtractor(), new DefaultSignProvider())
- *    Implements from <a href="https://github.com/apache/shenyu/issues/4208">#4208</a>
+ *    Version 1: 2.5.0 SignService
+ *    Version 2:Implements from <a href="https://github.com/apache/shenyu/issues/4208">#4208</a>
  *    parameters:
  *     {
  *           "alg":"HMD5",
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java
index d01ab38f0..bce19304f 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/extractor/DefaultExtractorTest.java
@@ -29,6 +29,8 @@ import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.Map;
 
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 
@@ -37,12 +39,27 @@ public class DefaultExtractorTest {
     private final SignParameterExtractor extractor = new DefaultExtractor();
 
     @Test
-    public void testExtract() {
+    public void testVersionOneExtract() {
+
+        HttpRequest httpRequest = MockServerHttpRequest
+                .get("http://localhost:9195/springcloud/class/annotation/get?id=1&id=1")
+                .header("timestamp", "1660659201000")
+                .header("appKey", "BD7980F5688A4DE6BCF1B5327FE07F5C")
+                .header("version", VERSION_1)
+                .header("sign", "BF485842D2C08A3378308BA9992A309F")
+                .build();
+
+        SignParameters signParameters = new SignParameters(VERSION_1, "BD7980F5688A4DE6BCF1B5327FE07F5C", "1660659201000",
+                "BF485842D2C08A3378308BA9992A309F", httpRequest.getURI(), "MD5");
+        assertThat(extractor.extract(httpRequest).toString(), is(signParameters.toString()));
+    }
+
+    @Test
+    public void testVersionTwoExtract() {
 
         Map<String, String> map = ImmutableMap.of(
                 "timestamp", "1660659201000",
                 "appKey", "BD7980F5688A4DE6BCF1B5327FE07F5C",
-                "version", "1.0.0",
                 "sign", "BF485842D2C08A3378308BA9992A309F",
                 "alg", "MD5");
 
@@ -52,8 +69,9 @@ public class DefaultExtractorTest {
         HttpRequest httpRequest = MockServerHttpRequest
                 .get("http://localhost:9195/springcloud/class/annotation/get?id=1&id=1")
                 .header(HttpHeaders.AUTHORIZATION, token)
+                .header("version", VERSION_2)
                 .build();
-        SignParameters signParameters = new SignParameters("BD7980F5688A4DE6BCF1B5327FE07F5C", "1660659201000",
+        SignParameters signParameters = new SignParameters(VERSION_2, "BD7980F5688A4DE6BCF1B5327FE07F5C", "1660659201000",
                 "BF485842D2C08A3378308BA9992A309F", httpRequest.getURI(), "MD5");
         signParameters.setParameters(parameters);
         assertThat(extractor.extract(httpRequest).toString(), is(signParameters.toString()));
diff --git a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java
index abe043d2f..5d4a84d02 100644
--- a/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java
+++ b/shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/provider/DefaultSignProviderTest.java
@@ -35,33 +35,32 @@ public class DefaultSignProviderTest {
 
     @Test
     void testGenerateSign() {
-        SignParameters signParameters = new SignParameters("108C27175A2C43C1BC29B1E483D57E3D",
+        SignParameters signParameters = new SignParameters("2.0.0", "108C27175A2C43C1BC29B1E483D57E3D",
                 "1673093719090", "C25A751BBCE25392DF61B352A2440FF9",
                 URI.create("http://localhost:9195/http/test/path/456?name=Lee&data=3"));
         String token = JsonUtils.toJson(ImmutableMap.of("alg", "MD5",
-                "version", "1.0.0",
                 "appKey", "108C27175A2C43C1BC29B1E483D57E3D",
                 "timestamp", "1673093719090"));
         signParameters.setParameters(Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)));
 
         String actual = signProvider.generateSign("061521A73DD94A3FA873C25D050685BB", signParameters);
-        assertThat(actual, is("AC53FD0F51F57DD18FE6861BB97E9F01"));
+        assertThat(actual, is("4892285C655127FE0B05BCAA4A47B093"));
     }
 
     @Test
     void testGenerateSignWithBody() {
-        SignParameters signParameters = new SignParameters("108C27175A2C43C1BC29B1E483D57E3D",
+        SignParameters signParameters = new SignParameters("2.0.0", "108C27175A2C43C1BC29B1E483D57E3D",
                 "1673093719090", "C25A751BBCE25392DF61B352A2440FF9",
                 URI.create("http://localhost:9195/http/test/payment?userName=Lee&userId=3"));
 
-        String token = JsonUtils.toJson(ImmutableMap.of("alg", "MD5",
-                "version", "1.0.0",
+        String token = JsonUtils.toJson(ImmutableMap.of(
+                "alg", "MD5",
                 "appKey", "108C27175A2C43C1BC29B1E483D57E3D",
                 "timestamp", "1673093719090"));
         signParameters.setParameters(Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)));
 
         ImmutableMap<String, String> requestBody = ImmutableMap.of("userName", "Lee", "userId", "3");
         String actual = signProvider.generateSign("061521A73DD94A3FA873C25D050685BB", signParameters, JsonUtils.toJson(requestBody));
-        assertThat(actual, is("725D6157459EFCDD2428D7BADA779077"));
+        assertThat(actual, is("61A097079016A18B1246A375482BEDBC"));
     }
 }
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/SignServiceVersionOneTest.java
similarity index 73%
copy from shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
copy to shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionOneTest.java
index 56e8c2213..0b50c5818 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/SignServiceVersionOneTest.java
@@ -25,8 +25,8 @@ 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.DigestUtils;
 import org.apache.shenyu.common.utils.JsonUtils;
-import org.apache.shenyu.common.utils.SignUtils;
 import org.apache.shenyu.plugin.api.context.ShenyuContext;
 import org.apache.shenyu.plugin.api.result.ShenyuResultEnum;
 import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
@@ -43,20 +43,19 @@ import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.http.HttpHeaders;
 import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
 import org.springframework.mock.web.server.MockServerWebExchange;
 import org.springframework.web.server.ServerWebExchange;
 
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_1;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.Mockito.mock;
 
@@ -65,7 +64,7 @@ import static org.mockito.Mockito.mock;
  */
 @ExtendWith(MockitoExtension.class)
 @MockitoSettings(strictness = Strictness.LENIENT)
-public final class DefaultSignServiceTest {
+public final class SignServiceVersionOneTest {
 
     private SignService signService;
 
@@ -120,10 +119,10 @@ public final class DefaultSignServiceTest {
     @Test
     public void normalTest() {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -132,11 +131,11 @@ public final class DefaultSignServiceTest {
 
     @Test
     public void nullTimestampTest() {
-
-        String parameters = buildParameters(null, appKey);
+        String timestamp = String.valueOf(System.currentTimeMillis());
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                null,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -147,9 +146,9 @@ public final class DefaultSignServiceTest {
     public void nullSignTest() {
 
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
+                timestamp,
+                appKey,
                 null);
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
@@ -163,12 +162,11 @@ public final class DefaultSignServiceTest {
 
     @Test
     public void nullAppKeyTest() {
-
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, null);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                timestamp,
+                null,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -178,10 +176,10 @@ public final class DefaultSignServiceTest {
     @Test
     public void overdueTest() {
         String errorTimestamp = String.valueOf(System.currentTimeMillis() - ((long) (delay + 1) * 1000 * 60));
-        String parameters = buildParameters(errorTimestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                errorTimestamp,
+                appKey,
+                buildSign(secretKey, errorTimestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -190,12 +188,11 @@ public final class DefaultSignServiceTest {
 
     @Test
     public void errorAppKeyTest() {
-
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, "errorKey");
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign("errorKey", parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                timestamp,
+                "errorKey",
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -206,10 +203,10 @@ public final class DefaultSignServiceTest {
     public void emptyAuthPath() {
 
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         AppAuthData authData = SignAuthDataCache.getInstance().obtainAuthData(appKey);
@@ -223,10 +220,10 @@ public final class DefaultSignServiceTest {
     @Test
     public void fillParamPath() {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         AppAuthData authData = SignAuthDataCache.getInstance().obtainAuthData(appKey);
@@ -243,10 +240,10 @@ public final class DefaultSignServiceTest {
     @Test
     public void emptyParamPath() {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), null));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         AppAuthData authData = SignAuthDataCache.getInstance().obtainAuthData(appKey);
@@ -259,10 +256,10 @@ public final class DefaultSignServiceTest {
     @Test
     public void errorAuthPath() {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/errorPath",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/errorPath"), null));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/errorPath", null, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -272,9 +269,10 @@ public final class DefaultSignServiceTest {
     @Test
     public void errorSign() {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters, "errorSign");
+                timestamp,
+                appKey,
+                "errorSign");
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange);
@@ -284,9 +282,9 @@ public final class DefaultSignServiceTest {
     @Test
     public void errorBodySign() {
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
+                timestamp,
+                appKey,
                 "errorSign");
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
@@ -298,14 +296,14 @@ public final class DefaultSignServiceTest {
 
     @Test
     public void bodySign() {
+
         Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(1);
         requestBody.put("data", "data");
-
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test"), JsonUtils.toJson(requestBody)));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", requestBody, null));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
 
         VerifyResult ret = this.signService.signatureVerify(this.exchange, JsonUtils.toJson(requestBody));
@@ -316,43 +314,48 @@ public final class DefaultSignServiceTest {
     public void bodyAndUrlQueryParamsSign() {
         Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(1);
         requestBody.put("data", "data");
+        Map<String, String> queryParams = Maps.newHashMapWithExpectedSize(1);
+        queryParams.put("data2", "data");
 
         String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
         this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test?data2=data",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test?data2=data"), JsonUtils.toJson(requestBody)));
+                timestamp,
+                appKey,
+                buildSign(secretKey, timestamp, "/test-api/demo/test", requestBody, queryParams));
         this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
-
         VerifyResult ret = this.signService.signatureVerify(this.exchange, JsonUtils.toJson(requestBody));
         assertEquals(ret, VerifyResult.success());
     }
 
-    @Test
-    public void errorBodyAndUrlQueryParamsSign() {
-        Map<String, String> requestBody = Maps.newHashMapWithExpectedSize(1);
-        requestBody.put("data", "data");
+    private String buildSign(final String signKey, final String timeStamp, final String path, final Map<String, String> jsonParams, final Map<String, String> queryParams) {
 
-        String timestamp = String.valueOf(System.currentTimeMillis());
-        String parameters = buildParameters(timestamp, appKey);
-        this.exchange = buildServerWebExchange("http://localhost/test-api/demo/test?data=data",
-                parameters,
-                buildSign(secretKey, parameters, URI.create("http://localhost/test-api/demo/test?data=data"), JsonUtils.toJson(requestBody)));
-        this.exchange.getAttributes().put(Constants.CONTEXT, this.passed);
+        Map<String, String> params = Maps.newHashMap(Optional.ofNullable(jsonParams)
+                .orElse(Collections.EMPTY_MAP));
 
-        // Tamper with request body parameters
-        requestBody.put("data", "data2");
-        VerifyResult ret = this.signService.signatureVerify(this.exchange, JsonUtils.toJson(requestBody));
-        assertEquals(ret, VerifyResult.fail(Constants.SIGN_VALUE_IS_ERROR));
-    }
+        params.putAll(Maps.newHashMap(Optional.ofNullable(queryParams)
+                .orElse(Collections.EMPTY_MAP)));
 
-    private String buildSign(final String signKey, final String parameters, final URI url, final String body) {
+        params.put(Constants.TIMESTAMP, timeStamp);
+        params.put(Constants.PATH, path);
+        params.put(Constants.VERSION, "1.0.0");
+
+        final String sign = params.keySet().stream()
+                .sorted(Comparator.naturalOrder())
+                .filter(key -> !Objects.equals(key, Constants.SIGN))
+                .map(key -> String.join("", key, params.get(key)))
+                .collect(Collectors.joining()).trim()
+                .concat(signKey);
+
+        return DigestUtils.md5Hex(sign.getBytes()).toUpperCase();
+    }
 
-        String data = parameters + getRelativeURL(url) + Optional.ofNullable(body).orElse("");
-        return SignUtils.sign(SignUtils.SIGN_MD5, signKey, data).toUpperCase();
+    private MockServerHttpRequest buildMockServerHttpRequest(final String url, final Map<String, String> headers) {
+        MockServerHttpRequest.BaseBuilder<?> builder = MockServerHttpRequest.get(url);
+        headers.forEach(builder::header);
+        return builder.build();
     }
 
-    private String buildParameters(final String timestamp, final String appKey) {
+    private ServerWebExchange buildServerWebExchange(final String url, final String timestamp, final String appKey, final String sign) {
         Map<String, String> map = new HashMap<>();
         if (timestamp != null) {
             map.put(Constants.TIMESTAMP, timestamp);
@@ -360,22 +363,11 @@ public final class DefaultSignServiceTest {
         if (appKey != null) {
             map.put(Constants.APP_KEY, appKey);
         }
-        map.put("alg", "MD5");
-        map.put("version", "1.0.0");
-        return Base64.getEncoder().encodeToString(JsonUtils.toJson(map).getBytes(StandardCharsets.UTF_8));
-    }
-
-    private ServerWebExchange buildServerWebExchange(final String url, final String parameters, final String sign) {
-
-        return MockServerWebExchange
-                .builder(MockServerHttpRequest.get(url)
-                        .header(HttpHeaders.AUTHORIZATION, Objects.isNull(sign) ? parameters : parameters + "." + sign)).build();
-    }
-
-    private String getRelativeURL(final URI uri) {
-        if (Objects.isNull(uri.getQuery())) {
-            return uri.getPath();
+        if (sign != null) {
+            map.put(Constants.SIGN, sign);
         }
-        return uri.getPath() + "?" + uri.getQuery();
+        map.put(Constants.VERSION, VERSION_1);
+        return MockServerWebExchange.builder(buildMockServerHttpRequest(url, map)).build();
     }
+
 }
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/SignServiceVersionTwoTest.java
similarity index 98%
rename from shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/DefaultSignServiceTest.java
rename to shenyu-plugin/shenyu-plugin-sign/src/test/java/org/apache/shenyu/plugin/sign/service/SignServiceVersionTwoTest.java
index 56e8c2213..514fe88c5 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/SignServiceVersionTwoTest.java
@@ -57,6 +57,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 
+import static org.apache.shenyu.plugin.sign.extractor.DefaultExtractor.VERSION_2;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.Mockito.mock;
 
@@ -65,7 +66,7 @@ import static org.mockito.Mockito.mock;
  */
 @ExtendWith(MockitoExtension.class)
 @MockitoSettings(strictness = Strictness.LENIENT)
-public final class DefaultSignServiceTest {
+public final class SignServiceVersionTwoTest {
 
     private SignService signService;
 
@@ -361,7 +362,6 @@ public final class DefaultSignServiceTest {
             map.put(Constants.APP_KEY, appKey);
         }
         map.put("alg", "MD5");
-        map.put("version", "1.0.0");
         return Base64.getEncoder().encodeToString(JsonUtils.toJson(map).getBytes(StandardCharsets.UTF_8));
     }
 
@@ -369,7 +369,8 @@ public final class DefaultSignServiceTest {
 
         return MockServerWebExchange
                 .builder(MockServerHttpRequest.get(url)
-                        .header(HttpHeaders.AUTHORIZATION, Objects.isNull(sign) ? parameters : parameters + "." + sign)).build();
+                        .header(HttpHeaders.AUTHORIZATION, Objects.isNull(sign) ? parameters : parameters + "." + sign)
+                        .header(Constants.VERSION, VERSION_2)).build();
     }
 
     private String getRelativeURL(final URI uri) {