Skip to main content
Version: 2.5.0

1. Overview

1.1 Plugin Name#

  • Sign Plugin

1.2 Appropriate Scenario#

  • Support http header to authorize
  • Support http header and request body to authorize

1.3 Plugin functionality#

  • Process signature authentication of requests.

1.4 Plugin code#

  • Core Module: shenyu-plugin-sign

  • Core Class: org.apache.shenyu.plugin.sign.SignPlugin

1.5 Added Since Which shenyu version#

  • Since ShenYu 2.4.0

2. How to use plugin

2.1 Plugin-use procedure chart#

2.2 Import pom#

  • Introducing sign dependency in the pom.xml file of the gateway
<!-- apache shenyu sign plugin start--><dependency>  <groupId>org.apache.shenyu</groupId>  <artifactId>shenyu-spring-boot-starter-plugin-sign</artifactId>  <version>${project.version}</version></dependency><!-- apache shenyu sign plugin end-->

2.3 Enable plugin#

  • In shenyu-admin--> BasicConfig --> Plugin --> sign set to enable.

2.4 Config Plugin With Authorize#

2.4.1 AK/SK Config#

2.4.1.1 Explanation#

  • Manage and control the permissions of requests passing through the Apache ShenYu gateway.
  • Generate AK/SK and use it with the Sign plugin to achieve precise authority control based on URI level.

2.4.1.2 Tutorial#

First, we can add a piece of authentication information in BasicConfig - Authentication

Then configure this authentication information

  • AppName:The application name associated with this account, it can can fill in or choose (data comes from the application name configured in the Metadata).
  • TelPhone:Telphone information.
  • AppParams:When the requested context path is the same as the AppName,add this value to the header, the key is appParam.
  • UserId:Give the user a name, just as an information record.
  • ExpandInfo:Description of the account.
  • PathAuth:After opening, the account only allows access to the resource path configured below.
  • ResourcePath:Allow access to the resource path, support path matching,e.g. /order/** .

After submit, a piece of authentication information is generated, which contains AppKey and AppSecret, which is the AK/SK in the Sign plugin.

Please refer to the detailed instructions of the Sign plugin: Sign Plugin.

2.4.1.3 PathOperation#

For the created authentication information, you can click PathOperation at the end of a piece of authentication information.

  • On the left is a list of configurable paths, and on the right is a list of paths that allow the account to access.
  • Check the resource path, click the > or < in the middle to move the checked data to the corresponding list.
  • In the list of configurable paths on the left, click "Editor" at the end of the account information line, and add them in the "Resource Path" in the pop-up box.

2.4.2 Implementation of Gateway Technology#

  • Adopt AK/SK authentication technical scheme.
  • Adopt authentication plug-in and Chain of Responsibility Pattern to realize.
  • Take effect when the authentication plugin is enabled and all interfaces are configured for authentication.

2.4.3 Authentication Guide#

  • Step 1: AK/SK is assigned by the gateway. For example, the AK assigned to you is: 1TEST123456781 SK is: ` 506eeb535cf740d7a755cb49f4a1536'

  • Step 2: Decide the gateway path you want to access, such as /api/service/abc

  • Step 3: Construct parameters (the following are general parameters)

FieldValueDescription
timestampcurrent timestamp(String)The number of milliseconds of the current time(gateway will filter requests the before 5 minutes)
path/api/service/abcThe path that you want to request(Modify by yourself according to your configuration of gateway)
version1.0.01.0.0 is a fixed string value

Sort the above three field natually according to the key, then splice fields and fields, finally splice SK. The following is a code example.

2.4.3.1 Generate sign with request header#

Step 1: First, construct a Map.


   Map<String, String> map = Maps.newHashMapWithExpectedSize(3);   //timestamp is string format of millisecond. String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli())   map.put("timestamp","1571711067186");  // Value should be string format of milliseconds   map.put("path", "/api/service/abc");   map.put("version", "1.0.0");

Step 2: Sort the Keys naturally, then splice the key and values, and finally splice the SK assigned to you.

List<String> storedKeys = Arrays.stream(map.keySet()                .toArray(new String[]{}))                .sorted(Comparator.naturalOrder())                .collect(Collectors.toList());final String sign = storedKeys.stream()                .map(key -> String.join("", key, params.get(key)))                .collect(Collectors.joining()).trim()                .concat("506EEB535CF740D7A755CB4B9F4A1536");
  • The returned sign value should be:path/api/service/abctimestamp1571711067186version1.0.0506EEB535CF740D7A755CB4B9F4A1536

Step 3: Md5 encryption and then capitalization.

DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()
  • The final returned value is: A021BF82BE342668B78CD9ADE593D683.

2.4.3.2 Generate sign with request header and request body#

Step 1: First, construct a Map, and the map must save every request body parameters


   Map<String, String> map = Maps.newHashMapWithExpectedSize(3);   //timestamp is string format of millisecond. String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli())   map.put("timestamp","1660659201000");  // Value should be string format of milliseconds   map.put("path", "/http/order/save");   map.put("version", "1.0.0");   // if your request body is:{"id":123,"name":"order"}   map.put("id", "1");   map.put("name", "order")

Step 2: Sort the Keys naturally, then splice the key and values, and finally splice the SK assigned to you.

List<String> storedKeys = Arrays.stream(map.keySet()                .toArray(new String[]{}))                .sorted(Comparator.naturalOrder())                .collect(Collectors.toList());final String sign = storedKeys.stream()                .map(key -> String.join("", key, params.get(key)))                .collect(Collectors.joining()).trim()                .concat("2D47C325AE5B4A4C926C23FD4395C719");
  • The returned sign value should be:id123nameorderpath/http/order/savetimestamp1660659201000version1.0.02D47C325AE5B4A4C926C23FD4395C719

Step 3: Md5 encryption and then capitalization.

DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()
  • The final returned value is: 35FE61C21F73E9AAFC46954C14F299D7.

2.4.4 Request GateWay#

  • If your visited path is:/api/service/abc.

  • Address: http: domain name of gateway /api/service/abc.

  • Set headerheader Parameter:

FieldValueDescription
timestamp1571711067186Timestamp when signing
appKey1TEST123456781The AK value assigned to you
signA90E66763793BDBC817CF3B52AAAC041The signature obtained above
version1.0.01.0.0 is a fixed value.
  • The signature plugin will filter requests before 5 minutes by default

  • If the authentication fails, will return code 401, message may change.

{  "code": 401,  "message": "sign is not pass,Please check you sign algorithm!",  "data": null}

2.4.5 Plugin Config#

2.4.6 Selector Config#

  • Only those matched requests can be authenticated by signature.

  • Selectors and rules, please refer to: Selector And Rule Config

2.4.7 Rule Config#

  • close(signRequestBody): generate signature with request header.
  • open(signRequestBody): generate signature with request header and request body.

2.5 Examples#

2.5.1 Verify api with sign plugin#

2.5.1.1 Plugin Config#

2.5.1.2 Selector Config#

2.5.1.3 Rule Config#

2.5.1.5 Add AppKey/SecretKey#

2.5.1.6 Request Service and check result#

  • build request params with Authentication Guide,
public class Test1 {  public static void main(String[] args) {    Map<String, String> map = Maps.newHashMapWithExpectedSize(3);    //timestamp为毫秒数的字符串形式 String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli())    map.put("timestamp","1660658725000");  //值应该为毫秒数的字符串形式    map.put("path", "/http/order/save");    map.put("version", "1.0.0");    map.put("id", "123");    map.put("name", "order");    // map.put("body", "{\"id\":123,\"name\":\"order\"}");
    List<String> storedKeys = Arrays.stream(map.keySet()                    .toArray(new String[]{}))            .sorted(Comparator.naturalOrder())            .collect(Collectors.toList());    final String sign = storedKeys.stream()            .map(key -> String.join("", key, map.get(key)))            .collect(Collectors.joining()).trim()            .concat("2D47C325AE5B4A4C926C23FD4395C719");    System.out.println(sign);
    System.out.println(DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase());  }}
  • signature without body: path/http/order/savetimestamp1571711067186version1.0.02D47C325AE5B4A4C926C23FD4395C719
  • sign without body result is: 9696D3E549A6AEBE763CCC2C7952DDC1

public class Test2 {  public static void main(String[] args) {    Map<String, String> map = Maps.newHashMapWithExpectedSize(3);    //timestamp为毫秒数的字符串形式 String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli())    map.put("timestamp","1660659201000");  //值应该为毫秒数的字符串形式    map.put("path", "/http/order/save");    map.put("version", "1.0.0");
    List<String> storedKeys = Arrays.stream(map.keySet()                    .toArray(new String[]{}))            .sorted(Comparator.naturalOrder())            .collect(Collectors.toList());    final String sign = storedKeys.stream()            .map(key -> String.join("", key, map.get(key)))            .collect(Collectors.joining()).trim()            .concat("2D47C325AE5B4A4C926C23FD4395C719");    System.out.println(sign);
    System.out.println(DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase());  }}

signature with body:id123nameorderpath/http/order/savetimestamp1660659201000version1.0.02D47C325AE5B4A4C926C23FD4395C719sign with body result is:35FE61C21F73E9AAFC46954C14F299D7

3. How to disable plugin

  • In shenyu-admin--> BasicConfig --> Plugin --> sign set to disabled.

4. Extension