Apache ShenYu 网关签名实战:AK/SK鉴权技术详解
此文档编写时使用的版本为 Apache ShenYu 2.6.0
Sign插件,用来对请求进行签名认证,支持请求头进行鉴权和请求体进行鉴权。
- 采用
AK/SK
鉴权技术方案。 - 采用鉴权插件,责任链的模式来完成。
- 当鉴权插件开启,并配置所有接口鉴权时候生效。
一 插件的鉴权配置
sign插件的 1.0.0 版本
- 第一步:AK/SK由网关来进行分配,比如分配给你的AK为:
CBB993DD88CF4A119F6FD771C963976B
SK为:FE9C196A16C44F649F07A9F640AA7691
- 第二步:确定好你要访问的网关路径 比如
/pub/captcha
- 第三步:构造参数(以下是通用参数)
字段 | 值 | 描述 |
---|---|---|
timestamp | 当前时间戳(String类型) | 当前时间的毫秒数(网关会过滤掉10分钟之前的请求) |
path | /pub/captcha | 就是你需要访问的接口路径(根据你访问网关接口自己变更) |
version | 1.0.0 | 当前鉴权算法为1.0.0 |
对上述3个字段进行 key
的自然排序,然后进行字段与字段值拼接最后再拼接上 SK
,代码示例。
1)无请求体的签名参数验证
第一步:首先构造一个 Map
。
//timestamp为毫秒数的字符串形式 String.valueOf(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli())
Map<String, String> map = Maps.newHashMapWithExpectedSize(3);
map.put("timestamp", "1725500864289"); //值应该为毫秒数的字符串形式
map.put("path", "/pub/captcha");
map.put("version", "1.0.0");
第二步:进行 Key
的自然排序,然后 Key
,Value
值拼接最后再拼接分配给你的 SK
。
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("FE9C196A16C44F649F07A9F640AA7691");
你得到的 sign
值应该为:
path/pub/captchatimestamp1725500864289version1.0.0FE9C196A16C44F649F07A9F640AA7691
第三步:进行 MD5
加密后转成大写。
DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()
最后得到的值为:
5D8C6E2E06E9AF128647EC6C3D27F31C
2) 有请求体,请求头的签名参数验证
第一步: 首先构造一个 Map
。并且该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", "1725500864289"); // Value should be string format of milliseconds
map.put("path", "/sys/lgn");
map.put("version", "1.0.0");
// if your request body is:{"mobile":"13688889999","password":"awlxninsnregxljprx8yvhzilm0tnhda","key":"53a55746-ee0f-4b5c-8750-1a9694d8c730","captcha":"qMvN"}
map.put("mobile", "13688889999");
map.put("password", "awlxninsnregxljprx8yvhzilm0tnhda");
map.put("key", "53a55746-ee0f-4b5c-8750-1a9694d8c730");
map.put("captcha", "qMvN");
第二步:进行 Key
的自然排序,然后 Key
,Value
值拼接最后再拼接分配给你的 SK
。
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("FE9C196A16C44F649F07A9F640AA7691");
- 你得到的
sign
值应该为:captchaqMvNkey53a55746-ee0f-4b5c-8750-1a9694d8c730mobile13688889999passwordawlxninsnregxljprx8yvhzilm0tnhdapath/sys/lgntimestamp1725500864289version1.0.0FE9C196A16C44F649F07A9F640AA7691
第三步:进行 MD5
加密后转成大写。
DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()
- 最后得到的值为:
6D8BCA2A50F33A8F98A3E8E8D958BBB9
.
二 示例请求网关
-
假如你访问的路径为:
/pub/captcha
。 -
访问地址 :
http://你的域名/pub/captcha。
-
设置
header
头,header
头参数为:
字段 | 值 | 描述 |
---|---|---|
timestamp | 1725500864289 | 上述你进行签名的时候使用的时间值 |
appKey | CBB993DD88CF4A119F6FD771C963976B | 分配给你的AK值 |
sign | 5D8C6E2E06E9AF128647EC6C3D27F31C | 上述得到的签名值 |
version | 1.0.0 | 写死,就为这个值 |
- 签名插件会默认过滤
10
分钟之前的请求(默认值参考官方文档,这里有做修改) - 如果认证不通过会返回
code
为401
,message
可能会有变动。
{ "code": 401, "message": "sign is not pass,Please check you sign algorithm!", "data": null}
详情参考:Apache ShenYu 的 SignPlugin 插件