核心模块: shenyu-plugin-sign
核心类: org.apache.shenyu.plugin.sign.SignPlugin
pom.xml
文件中添加 sign
的支持。<!-- 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
基础配置 --> 插件管理 --> sign
,设置为开启。Apache ShenYu
网关的请求的权限。AK/SK
,配合 sign
插件使用,实现基于URI
级别的精准权限管控。第一步,我们可以直接在 基础配置
--> 认证管理
新增一条认证信息 。
第二步,配置这条认证信息 。
appParam
。/order/**
。点击确认后,生成一条认证信息,该信息包含 AppKey
和 加密秘钥
,即 Sign
插件中的 AK/SK
。
对已创建的认证信息,可以在认证信息列表的末尾进行 路径操作
。
>
或 <
将勾选的数据移动到对应列表中 。编辑
,在弹框中的 资源路径
中进行添加 。AK/SK
鉴权技术方案。第一步:AK/SK由网关来进行分配,比如分配给你的AK为: 1TEST123456781
SK为:506EEB535CF740D7A755CB4B9F4A1536
第二步:确定好你要访问的网关路径 比如 /api/service/abc
第三步:构造参数(以下是通用参数)
字段 | 值 | 描述 |
---|---|---|
timestamp | 当前时间戳(String类型) | 当前时间的毫秒数(网关会过滤掉5分钟之前的请求) |
path | /api/service/abc | 就是你需要访问的接口路径(根据你访问网关接口自己变更) |
version | 1.0.0 | 目前定为1.0.0 写死,String类型 |
对上述3个字段进行字段与字段值拼接最后再拼接上 SK
作为extSignKey
,代码示例。
第一步:首先构造一个 extSignKey
。
//timestamp为毫秒数的字符串形式 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");
extSignKey
值应该为:timestamp1571711067186path/api/service/abcversion1.0.0506EEB535CF740D7A755CB4B9F4A1536
第二步:进行 MD5
加密后转成大写。
DigestUtils.md5DigestAsHex(extSignKey.getBytes()).toUpperCase()
F6A9EE877F1C017AF60D8F1200517AA5
uri
请求参数,请求头的签名参数验证第一步:首先构造一个 extSignKey
。
//timestamp为毫秒数的字符串形式 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");
extSignKey
值应该为:timestamp1571711067186path/api/service/abcversion1.0.0506EEB535CF740D7A755CB4B9F4A1536
第二步: 构造一个 Map
名为 jsonMap
。并且该jsonMap
必须存储请求体的每个节点信息
//无请求体跳过此步 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
名为 queryMap
。并且该queryMap
必须存储uri请求参数的每个节点信息
//无url请求参数跳过此步 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");
第四步: jsonMap
和 queryMap
分别进行 Key
的自然排序,然后 Key
,Value
值拼接得到jsonSign
和 querySign
,最后拼接jsonSign
、 querySign
、extSignKey
为 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);
sign
值应该为:id123nameordercode10descdesctimestamp1571711067186path/api/service/abcversion1.0.0506EEB535CF740D7A755CB4B9F4A1536
第三步:进行 MD5
加密后转成大写。
DigestUtils.md5DigestAsHex(sign.getBytes()).toUpperCase()
AC8EB7C4E0DAC57C4FCF8A9C58A3E445
.假如你访问的路径为:/api/service/abc
。
访问地址 :http:网关的域名/api/service/abc
。
设置header
头,header
头参数为:
字段 | 值 | 描述 |
---|---|---|
timestamp | 1571711067186 | 上述你进行签名的时候使用的时间值 |
appKey | 1TEST123456781 | 分配给你的AK值 |
sign | AC8EB7C4E0DAC57C4FCF8A9C58A3E445 | 上述得到的签名值 |
version | 1.0.0 | 写死,就为这个值 |
签名插件会默认过滤 5
分钟之前的请求
如果认证不通过会返回 code
为 401
, message
可能会有变动。
{ "code": 401, "message": "sign is not pass,Please check you sign algorithm!", "data": null }
只有匹配的请求,才会进行签名认证。
插件选择器和规则的配置请查看: 插件和规则配置.
Authentication Guide
目录,public class Test1 { public static void main(String[] args) { //timestamp为毫秒数的字符串形式 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为毫秒数的字符串形式 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()); } }
id123nameordertimestamp1660659201000path/http/order/saveversion1.0.02D47C325AE5B4A4C926C23FD4395C719
BF485842D2C08A3378308BA9992A309F
shenyu-admin
基础配置 --> 插件管理 --> sign
,设置为关闭。