Core Module: shenyu-plugin-sign
Core Class: org.apache.shenyu.plugin.sign.SignPlugin
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-->
shenyu-admin
--> BasicConfig --> Plugin --> sign
set to enable.AK/SK
and use it with the Sign
plugin to achieve precise authority control based on URI level.First, we can add a piece of authentication information in BasicConfig
- Authentication
Then configure this authentication information
appParam
./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.
For the created authentication information, you can click PathOperation
at the end of a piece of authentication information.
>
or <
in the middle to move the checked data to the corresponding list.AK/SK
authentication technical scheme.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)
Field | Value | Description |
---|---|---|
timestamp | current timestamp(String) | The number of milliseconds of the current time(gateway will filter requests the before 5 minutes) |
path | /api/service/abc | The path that you want to request(Modify by yourself according to your configuration of gateway) |
version | 1.0.0 | 1.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. The above three fields are spliced with field values, and then ‘SK’ is spliced as the 'extSignKey`. The following is a code example.
Step 1: First, construct a extSignKey
//timestamp is string format of millisecond. String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()) String timestamp = "1571711067186"; String path = "/api/service/abc"; String version = "1.0.0"; String extSignKey = String.join("", "timestamp", timestamp, "path", path, "version", version, "506EEB535CF740D7A755CB4B9F4A1536");
timestamp1571711067186path/api/service/abcversion1.0.0506EEB535CF740D7A755CB4B9F4A1536
Step 2: Md5 encryption and then capitalization.
DigestUtils.md5DigestAsHex(extSignKey.getBytes()).toUpperCase()
F6A9EE877F1C017AF60D8F1200517AA5
.Step 1: First, construct a extSignKey
//timestamp is string format of millisecond. String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()) String timestamp = "1571711067186"; String path = "/api/service/abc"; String version = "1.0.0"; String extSignKey = String.join("", "timestamp", timestamp, "path", path, "version", version, "506EEB535CF740D7A755CB4B9F4A1536");
timestamp1571711067186path/api/service/abcversion1.0.0506EEB535CF740D7A755CB4B9F4A1536
Step 2: Construct a ‘Map’ named ‘jsonMap’. And the ‘jsonMap’ must store the information of each node of the request body.
//Skip this step if there is no request body Map<String, String> jsonMap = Maps.newHashMapWithExpectedSize(2); // if your request body is:{"id":123,"name":"order"} jsonMap.put("id", "123"); jsonMap.put("name", "order");
Step 3: Construct a ‘Map’ named ‘queryMap’. And the ‘queryMap’ must store the information of each node of the uri request parameter.
//No url request parameter Skip this step Map<String, String> queryMap = Maps.newHashMapWithExpectedSize(2); // if your request uri is:/api/service/abc?code=10&desc="desc" queryMap.put("code", "10"); queryMap.put("desc", "desc");
Step 4: `JsonMap ‘and’ queryMap ‘respectively perform the natural sorting of’ Key ‘, then’ Key ‘and’ Value ‘values are spliced to obtain’ jsonSign ‘and’ querySign ‘, and finally’ jsonSign ‘,’ querySign ‘and’ extSignKey ‘are spliced to’ sign '.
Map<String, String> empityMap = new HashMap(); String jsonSign = Optional.ofNullable(jsonMap).orElse(empityMap).keySet().stream() .sorted(Comparator.naturalOrder()) .map(key -> String.join("", key, jsonMap.get(key))) .collect(Collectors.joining()).trim(); String querySign = Optional.ofNullable(queryMap).orElse(empityMap).keySet().stream() .sorted(Comparator.naturalOrder()) .map(key -> String.join("", key, queryMap.get(key))) .collect(Collectors.joining()).trim(); String sign = String.join("", jsonSign, querySign, signKey);
id123nameordercode10descdesctimestamp1571711067186path/api/service/abcversion1.0.0506EEB535CF740D7A755CB4B9F4A1536
Step 5: Md5 encryption and then capitalization.
DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()
AC8EB7C4E0DAC57C4FCF8A9C58A3E445
.If your visited path is:/api/service/abc
.
Address: http: domain name of gateway /api/service/abc
.
Set header
,header
Parameter:
Field | Value | Description |
---|---|---|
timestamp | 1571711067186 | Timestamp when signing |
appKey | 1TEST123456781 | The AK value assigned to you |
sign | AC8EB7C4E0DAC57C4FCF8A9C58A3E445 | The signature obtained above |
version | 1.0.0 | 1.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 }
Only those matched requests can be authenticated by signature.
Selectors and rules, please refer to: Selector And Rule Config
Authentication Guide
,public class Test1 { public static void main(String[] args) { //timestamp is string format of millisecond String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()) String timestamp = "1660658725000"; String path = "/http/order/save"; String version = "1.0.0"; String extSignKey = String.join("", "timestamp", timestamp, "path", path, "version", version, "2D47C325AE5B4A4C926C23FD4395C719"); System.out.println(extSignKey); System.out.println(DigestUtils.md5DigestAsHex(extSignKey.getBytes()).toUpperCase()); } }
timestamp1660658725000path/http/order/saveversion1.0.02D47C325AE5B4A4C926C23FD4395C719
A2D81371D99DD4ECB0D5EC6298E3C2EB
public class Test2 { public static void main(String[] args) { //timestamp is string format of millisecond String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()) String timestamp = "1660659201000"; String path = "/http/order/save"; String version = "1.0.0"; String extSignKey = String.join("", "timestamp", timestamp, "path", path, "version", version, "2D47C325AE5B4A4C926C23FD4395C719"); Map<String, String> jsonMap = Maps.newHashMapWithExpectedSize(2); // if your request body is:{"id":123,"name":"order"} jsonMap.put("id", "123"); jsonMap.put("name", "order"); Map<String, String> queryMap = null; /* if you have uri params Map<String, String> queryMap = Maps.newHashMapWithExpectedSize(2); // if your request uri is:/api/service/abc?code=10&desc="desc" queryMap.put("code", "10"); queryMap.put("desc", "desc"); */ Map<String, String> empityMap = new HashMap(); String jsonSign = Optional.ofNullable(jsonMap).orElse(empityMap).keySet().stream() .sorted(Comparator.naturalOrder()) .map(key -> String.join("", key, jsonMap.get(key))) .collect(Collectors.joining()).trim(); String querySign = Optional.ofNullable(queryMap).orElse(empityMap).keySet().stream() .sorted(Comparator.naturalOrder()) .map(key -> String.join("", key, queryMap.get(key))) .collect(Collectors.joining()).trim(); String sign = String.join("", jsonSign, querySign, signKey); System.out.println(sign); System.out.println(DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()); } }
*signature with body:id123nameordertimestamp1660659201000path/http/order/saveversion1.0.02D47C325AE5B4A4C926C23FD4395C719
*sign with body result is:BF485842D2C08A3378308BA9992A309F
shenyu-admin
--> BasicConfig --> Plugin --> sign
set to disabled.