title: Sign Plugin keywords: [“sign”] description: sign plugin

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.02D47C325AE5B4A4C926C23FD4395C719 *sign with body result is:35FE61C21F73E9AAFC46954C14F299D7

3. How to disable plugin

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

4. Extension