From aa2663e3f570432054c7a943ad1235de14382565 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Tue, 2 May 2023 03:22:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20getData=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E9=85=8D=E7=BD=AE=EF=BC=8C=E5=9C=A8=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=89=E6=8B=89=E5=8F=96=E6=95=B0=E6=8D=AE=E6=97=B6=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E4=BC=A0=E9=80=92=E4=BB=BB=E6=84=8F=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/context/model/SaRequest.java | 18 +- .../satoken/listener/SaTokenEventCenter.java | 8 +- .../satoken/listener/SaTokenListener.java | 6 +- .../listener/SaTokenListenerForLog.java | 10 +- .../cn/dev33/satoken/sign/SaSignTemplate.java | 71 ++++-- .../java/com/pj/sso/SsoServerController.java | 34 ++- .../java/com/pj/sso/SsoClientController.java | 21 +- .../src/main/resources/application.yml | 6 +- sa-token-doc/sso/sso-type3.md | 163 ++++++++----- .../dubbo/model/SaRequestForDubbo.java | 21 ++ .../dubbo3/model/SaRequestForDubbo3.java | 21 ++ .../context/grpc/model/SaRequestForGrpc.java | 21 ++ .../cn/dev33/satoken/config/SaSsoConfig.java | 61 +++-- .../cn/dev33/satoken/sso/SaSsoTemplate.java | 217 ++++++++++-------- .../java/cn/dev33/satoken/sso/SaSsoUtil.java | 112 ++++++--- .../satoken/sso/error/SaSsoErrorCode.java | 5 +- .../servlet/model/SaRequestForServlet.java | 35 ++- .../reactor/model/SaRequestForReactor.java | 21 ++ .../reactor/model/SaRequestForReactor.java | 24 ++ .../servlet/model/SaRequestForServlet.java | 31 +++ .../solon/model/SaRequestForSolon.java | 20 ++ 21 files changed, 668 insertions(+), 258 deletions(-) diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java index 12e92aa3..8dfb402e 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java @@ -4,6 +4,9 @@ import cn.dev33.satoken.error.SaErrorCode; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.util.SaFoxUtil; +import java.util.List; +import java.util.Map; + /** * Request 包装类 * @author kong @@ -70,8 +73,19 @@ public interface SaRequest { } return paramValue; } - - + + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + public List getParamNames(); + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + public Map getParamMap(); + /** * 在 [请求头] 里获取一个值 * @param name 键 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java index 1e9107df..4bb1890a 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenEventCenter.java @@ -262,12 +262,12 @@ public class SaTokenEventCenter { /** * 全局组件载入 - * @param comtName 组件名称 - * @param comtObj 组件对象 + * @param compName 组件名称 + * @param compObj 组件对象 */ - public static void doRegisterComponent(String comtName, Object comtObj) { + public static void doRegisterComponent(String compName, Object compObj) { for (SaTokenListener listener : listenerList) { - listener.doRegisterComponent(comtName, comtObj); + listener.doRegisterComponent(compName, compObj); } } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java index e71b4700..6cb6ffe8 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListener.java @@ -103,10 +103,10 @@ public interface SaTokenListener { /** * 全局组件载入 - * @param comtName 组件名称 - * @param comtObj 组件对象 + * @param compName 组件名称 + * @param compObj 组件对象 */ - public default void doRegisterComponent(String comtName, Object comtObj) {} + public default void doRegisterComponent(String compName, Object compObj) {} /** * StpLogic 对象替换 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForLog.java b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForLog.java index 9ef0a2da..8b763056 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForLog.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForLog.java @@ -106,13 +106,13 @@ public class SaTokenListenerForLog implements SaTokenListener { /** * 全局组件载入 - * @param comtName 组件名称 - * @param comtObj 组件对象 + * @param compName 组件名称 + * @param compObj 组件对象 */ @Override - public void doRegisterComponent(String comtName, Object comtObj) { - String canonicalName = comtObj == null ? null : comtObj.getClass().getCanonicalName(); - log.info("全局组件 {} 载入成功: {}", comtName, canonicalName); + public void doRegisterComponent(String compName, Object compObj) { + String canonicalName = compObj == null ? null : compObj.getClass().getCanonicalName(); + log.info("全局组件 {} 载入成功: {}", compName, canonicalName); } /** diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplate.java b/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplate.java index 0635105c..346e8773 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplate.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplate.java @@ -1,18 +1,18 @@ package cn.dev33.satoken.sign; -import java.util.Map; -import java.util.TreeMap; - import cn.dev33.satoken.error.SaErrorCode; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.secure.SaSecureUtil; import cn.dev33.satoken.util.SaFoxUtil; +import java.util.Map; +import java.util.TreeMap; + /** - * 参数签名算法 - * + * 参数签名算法 + * * @author kong - * @since: 2022-4-27 + * @since 2022-4-27 */ public interface SaSignTemplate { @@ -21,13 +21,13 @@ public interface SaSignTemplate { * @param paramsMap 参数列表 * @return 拼接出的参数字符串 */ - public default String joinParams(Map paramsMap) { + public default String joinParams(Map paramsMap) { // 按照 k1=v1&k2=v2&k3=v3 排列 StringBuilder sb = new StringBuilder(); for (String key : paramsMap.keySet()) { Object value = paramsMap.get(key); - if(SaFoxUtil.isEmpty(value) == false) { + if( ! SaFoxUtil.isEmpty(value) ) { sb.append(key).append("=").append(value).append("&"); } } @@ -46,9 +46,9 @@ public interface SaSignTemplate { * @param paramsMap 参数列表 * @return 拼接出的参数字符串 */ - public default String joinParamsDictSort(Map paramsMap) { + public default String joinParamsDictSort(Map paramsMap) { // 保证字段按照字典顺序排列 - if(paramsMap instanceof TreeMap == false) { + if( ! (paramsMap instanceof TreeMap) ) { paramsMap = new TreeMap<>(paramsMap); } @@ -62,9 +62,17 @@ public interface SaSignTemplate { * @param key 秘钥 * @return 签名 */ - public default String createSign(Map paramsMap, String key) { + public default String createSign(Map paramsMap, String key) { SaTokenException.throwByNull(key, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201); - + + // 如果调用者不小心传入了 sign 参数,则此处需要将 sign 参数排除在外 + // 为了保证不影响原有的 paramsMap,此处需要再复制一份 + if(paramsMap.containsKey("sign")) { + paramsMap = new TreeMap<>(paramsMap); + paramsMap.remove("sign"); + } + + // 计算签名 String paramsStr = joinParamsDictSort(paramsMap); String fullStr = paramsStr + "&key=" + key; return SaSecureUtil.md5(fullStr); @@ -77,7 +85,7 @@ public interface SaSignTemplate { * @param sign 待验证的签名 * @return 签名是否有效 */ - public default boolean isValidSign(Map paramsMap, String key, String sign) { + public default boolean isValidSign(Map paramsMap, String key, String sign) { String theSign = createSign(paramsMap, key); return theSign.equals(sign); } @@ -88,8 +96,8 @@ public interface SaSignTemplate { * @param key 秘钥 * @param sign 待验证的签名 */ - public default void checkSign(Map paramsMap, String key, String sign) { - if(isValidSign(paramsMap, key, sign) == false) { + public default void checkSign(Map paramsMap, String key, String sign) { + if( ! isValidSign(paramsMap, key, sign) ) { throw new SaTokenException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202); } } @@ -111,15 +119,15 @@ public interface SaSignTemplate { * 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如: * data=xxx8nonce=xxx8timestamp=xxx8sign=xxx * @param paramsMap 参数列表 - * @param key 秘钥 - * @return 加工后的参数列表 转化为的参数字符串 + * @param key 秘钥 + * @return 加工后的参数列表 转化为的参数字符串 */ - public default String addSignParamsToString(Map paramsMap, String key) { - // 追加参数 + public default String addSignParamsAndToString(Map paramsMap, String key) { + // 追加参数 paramsMap = addSignParams(paramsMap, key); - - // . - return joinParams(paramsMap); + + // . + return joinParams(paramsMap); } /** @@ -139,9 +147,26 @@ public interface SaSignTemplate { * @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制 */ public default void checkTimestamp(long timestamp, long allowDisparity) { - if(isValidTimestamp(timestamp, allowDisparity) == false) { + if( ! isValidTimestamp(timestamp, allowDisparity) ) { throw new SaTokenException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203); } } + // ------------------ 以下为兼容旧版本的方法 ------------------ + + /** + * 请更换为 addSignParamsAndToString + * @param paramsMap 参数列表 + * @param key 秘钥 + * @return 加工后的参数列表 转化为的参数字符串 + */ + @Deprecated + public default String addSignParamsToString(Map paramsMap, String key) { + // 追加参数 + paramsMap = addSignParams(paramsMap, key); + + // . + return joinParams(paramsMap); + } + } diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java index 9f6ecfce..8c72a99f 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/java/com/pj/sso/SsoServerController.java @@ -1,17 +1,17 @@ package com.pj.sso; +import cn.dev33.satoken.config.SaSsoConfig; +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.sso.SaSsoProcessor; +import cn.dev33.satoken.sso.SaSsoUtil; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; +import com.dtflys.forest.Forest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; -import com.dtflys.forest.Forest; - -import cn.dev33.satoken.config.SaSsoConfig; -import cn.dev33.satoken.sso.SaSsoProcessor; -import cn.dev33.satoken.stp.StpUtil; -import cn.dev33.satoken.util.SaResult; - /** * Sa-Token-SSO Server端 Controller * @author kong @@ -63,5 +63,23 @@ public class SsoServerController { } }); } - + + // 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口) + @RequestMapping("/sso/getData") + public Object userinfo(String apiType, String loginId) { + System.out.println("---------------- 获取数据 ----------------"); + System.out.println("apiType=" + apiType); + System.out.println("loginId=" + loginId); + + // 校验签名:只有拥有正确秘钥发起的请求才能通过校验 + SaSsoUtil.checkSign(SaHolder.getRequest()); + + // 自定义返回结果(模拟) + return SaResult.ok() + .set("id", loginId) + .set("name", "LinXiaoYu") + .set("sex", "女") + .set("age", 18); + } + } diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/sso/SsoClientController.java b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/sso/SsoClientController.java index 111340fb..cf1d77a0 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/sso/SsoClientController.java +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/java/com/pj/sso/SsoClientController.java @@ -1,5 +1,6 @@ package com.pj.sso; +import cn.dev33.satoken.context.SaHolder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; @@ -13,6 +14,10 @@ import cn.dev33.satoken.sso.SaSsoUtil; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaResult; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Sa-Token-SSO Client端 Controller * @author kong @@ -52,11 +57,17 @@ public class SsoClientController { } // 查询我的账号信息 - @RequestMapping("/sso/myinfo") - public Object myinfo() { - Object userinfo = SaSsoUtil.getUserinfo(StpUtil.getLoginId()); - System.out.println("--------info:" + userinfo); - return userinfo; + @RequestMapping("/sso/myInfo") + public Object myInfo() { + // 组织请求参数 + Map map = new HashMap<>(); + map.put("apiType", "userinfo"); + map.put("loginId", StpUtil.getLoginId()); + + // 发起请求 + Object resData = SaSsoUtil.getData("/sso/getData", map); + System.out.println("sso-server 返回的信息:" + resData); + return resData; } // 全局异常拦截 diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml index 5c2433d4..67632540 100644 --- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso3-client/src/main/resources/application.yml @@ -18,9 +18,9 @@ sa-token: slo-url: http://sa-sso-server.com:9000/sso/signout # 接口调用秘钥 secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor - # SSO-Server端 查询userinfo地址 - userinfo-url: http://sa-sso-server.com:9000/sso/userinfo - + # 查询数据地址 + get-data-url: http://sa-sso-server.com:9000/sso/getData + spring: # 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis) redis: diff --git a/sa-token-doc/sso/sso-type3.md b/sa-token-doc/sso/sso-type3.md index 336f7265..ea504b69 100644 --- a/sa-token-doc/sso/sso-type3.md +++ b/sa-token-doc/sso/sso-type3.md @@ -98,109 +98,160 @@ forest.log-enabled: false > 注:如果已测试运行模式二,可先将Redis中的数据清空,以防旧数据对测试造成干扰 -### 3、获取 Userinfo -除了账号id,我们可能还需要将用户的昵称、头像等信息从 Server端 带到 Client端,即:用户资料的同步。 +### 3、获取 UserInfo +除了账号id,我们可能还需要将用户的昵称、头像等信息从 Server端 带到 Client端,即:用户资料的拉取。 -在模式二中我们只需要将需要同步的资料放到 SaSession 即可,但是在模式三中两端不再连接同一个Redis,这时候我们需要通过http接口来同步信息: +在模式二中我们只需要将需要同步的资料放到 SaSession 即可,但是在模式三中两端不再连接同一个 Redis,这时候我们需要通过 http 接口来同步信息。 + +在旧版本`(<= v1.34.0)` 框架提供的方案是配置 getUserinfo 接口地址,从 client 调用拉取数据,该方案有以下缺点: +- 每次调用只能传递固定 loginId 一个参数,不方便。 +- 只能拉取 userinfo 数据,不通用。 +- 如果还需要拉取其它业务数据,需要再自定义一个接口,比较麻烦。 + +为此,我们设计了更通用、灵活的 getData 接口,解决上述三个难题。 + +#### 3.1、首先在 Server 端开放一个查询数据的接口 -#### 3.1、在 Server 端自定义接口,查询用户资料 ``` java -// 自定义接口:获取userinfo -@RequestMapping("/sso/userinfo") -public Object userinfo(String loginId) { - System.out.println("---------------- 获取userinfo --------"); - - // 校验签名,防止敏感信息外泄 +// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口) +@RequestMapping("/sso/getData") +public Object userinfo(String apiType, String loginId) { + System.out.println("---------------- 获取数据 ----------------"); + System.out.println("apiType=" + apiType); + System.out.println("loginId=" + loginId); + + // 校验签名:只有拥有正确秘钥发起的请求才能通过校验 SaSsoUtil.checkSign(SaHolder.getRequest()); // 自定义返回结果(模拟) return SaResult.ok() .set("id", loginId) - .set("name", "linxiaoyu") + .set("name", "LinXiaoYu") .set("sex", "女") .set("age", 18); } ``` -#### 3.2、在 Client 端调用此接口查询 userinfo +#### 3.2、在 Client 端调用此接口查询数据 + 首先在 application.yml 中配置接口地址: ``` yaml sa-token: sso: - # SSO-Server端 查询userinfo地址 - userinfo-url: http://sa-sso-server.com:9000/sso/userinfo + # sso-server 端拉取数据地址 + get-data-url: http://sa-sso-server.com:9000/sso/getData ``` ``` properties -# SSO-Server端 查询userinfo地址 -sa-token.sso.userinfo-url=http://sa-sso-server.com:9000/sso/userinfo +# sso-server 端拉取数据地址 +sa-token.sso.get-data-url=http://sa-sso-server.com:9000/sso/getData ``` - - -然后在`SsoClientController`中新增接口 +然后在 `SsoClientController` 中新增接口 ``` java // 查询我的账号信息 -@RequestMapping("/sso/myinfo") -public Object myinfo() { - Object userinfo = SaSsoUtil.getUserinfo(StpUtil.getLoginId()); - System.out.println("--------info:" + userinfo); - return userinfo; +@RequestMapping("/sso/myInfo") +public Object myInfo() { + // 组织请求参数 + Map map = new HashMap<>(); + map.put("apiType", "userinfo"); + map.put("loginId", StpUtil.getLoginId()); + + // 发起请求 + Object resData = SaSsoUtil.getData(map); + System.out.println("sso-server 返回的信息:" + resData); + return resData; } ``` #### 3.3、访问测试 -访问测试:[http://sa-sso-client1.com:9001/sso/myinfo](http://sa-sso-client1.com:9001/sso/myinfo) +访问测试:[http://sa-sso-client1.com:9001/sso/myInfo](http://sa-sso-client1.com:9001/sso/myInfo) ### 4、自定义接口通信 -群里有小伙伴提问:`SaSsoUtil.getUserinfo` 提供的参数太少,只有一个 loginId,无法满足业务需求怎么办? +上述示例展示在 client 端向 server 拉取 userinfo 数据的步骤,如果你还需要拉取其它业务的数据,稍加改造示例便可以实现。 -答:SaSsoUtil.getUserinfo只是为了避免你在项目中硬编码认证中心 url 而提供的简易封装,如果这个API无法满足你的业务需求, -你完全可以在 Server 端自定义一些接口然后从 Client 端使用 http 工具调用即可。 +#### 4.1、方式一,使用 apiType 参数来区分业务 -以下是一个简单的示例: +我们可以约定好,使用 apiType 来区分不同的业务,例如: +- 当 `apiType=userinfo` 时:代表拉取用户资料。 +- 当 `apiType=followList` 时:代表拉取用户的关注列表。 +- 当 `apiType=fansList` 时:代表拉取用户的粉丝列表。 -#### 4.1、先在 sso-server 端自定义一个接口 -``` java -// 获取指定用户的关注列表 -@RequestMapping("/sso/getFollowList") -public Object ssoRequest(Long loginId) { +此时,我们便可以通过在 client 端传入不同的 apiType 参数,来区分不同的业务。 - // 校验签名,签名不通过直接抛出异常 - SaSsoUtil.checkSign(SaHolder.getRequest()); - - // 查询数据 (此处仅做模拟) - List list = Arrays.asList(10041, 10042, 10043, 10044); - - // 返回 - return list; -} -``` - - -#### 4.2、然后在 sso-client 端调用这个接口 ``` java // 查询我的账号信息 @RequestMapping("/sso/myFollowList") public Object myFollowList() { - // 组织url,加上签名参数 - String url = SaSsoUtil.addSignParams("http://sa-sso-server.com:9000/sso/getFollowList", StpUtil.getLoginId()); - - // 调用,并返回 SaResult 结果 - SaResult res = SaSsoUtil.request(url); - - // 返回给前端 - return res; + // 组织请求参数 + Map map = new HashMap<>(); + map.put("apiType", "followList"); // 关键代码,代表本次我要拉取关注列表 + map.put("loginId", StpUtil.getLoginId()); + + // 发起请求 + Object resData = SaSsoUtil.getData(map); + System.out.println("sso-server 返回的信息:" + resData); + return resData; } ``` +然后在 server 端我们通过不同的 apiType 值,返回不同的信息即可。 + + +#### 4.2、方式二:直接在调用接口时传入一个自定义 path + +我们可以 client 端,调用 `SaSsoUtil.getData` 方法时,传入一个自定义 path,例如: + +``` java +// 查询我的账号信息 +@RequestMapping("/sso/myFansList") +public Object myFansList() { + // 组织请求参数 + Map map = new HashMap<>(); + // map.put("apiType", "userinfo"); // 此时已经不需要 apiType 参数了 + map.put("loginId", StpUtil.getLoginId()); + + // 发起请求 (传入自定义的 path 地址) + Object resData = SaSsoUtil.getData("/sso/getFansList", map); + System.out.println("sso-server 返回的信息:" + resData); + return resData; +} +``` + +同时,我们需要在 server 端开放这个自定义的 `/sso/getFansList` 接口: + +``` java +// 获取指定用户的粉丝列表 +@RequestMapping("/sso/getFansList") +public Object getFansList(Long loginId) { + System.out.println("---------------- 获取 loginId=" + loginId + " 的粉丝列表 ----------------"); + + // 校验签名:只有拥有正确秘钥发起的请求才能通过校验 + SaSsoUtil.checkSign(SaHolder.getRequest()); + + // 查询数据 (此处仅做模拟) + List list = Arrays.asList(10041, 10042, 10043, 10044); + + // 返回 + return list; +} +``` + +**注意:使用此方案时,需要在 client 端配置 `sa-token.sso.server-url` 地址,例如:** +``` yaml +sa-token: + sso: + # sso-server 端主机地址 + server-url: http://sa-sso-server.com:9000 +``` + #### 4.3、访问测试 -访问测试:[http://sa-sso-client1.com:9001/sso/myFollowList](http://sa-sso-client1.com:9001/sso/myFollowList) +访问测试:[http://sa-sso-client1.com:9001/sso/myFansList](http://sa-sso-client1.com:9001/sso/myFansList) diff --git a/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaRequestForDubbo.java b/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaRequestForDubbo.java index 3e506528..9ee00aea 100644 --- a/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaRequestForDubbo.java +++ b/sa-token-plugin/sa-token-context-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/model/SaRequestForDubbo.java @@ -4,6 +4,9 @@ import org.apache.dubbo.rpc.RpcContext; import cn.dev33.satoken.context.model.SaRequest; +import java.util.List; +import java.util.Map; + /** * Request for Dubbo * @@ -42,6 +45,24 @@ public class SaRequestForDubbo implements SaRequest { return null; } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + return null; + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + return null; + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-plugin/sa-token-context-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/model/SaRequestForDubbo3.java b/sa-token-plugin/sa-token-context-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/model/SaRequestForDubbo3.java index 655cdd95..b2efb9fd 100644 --- a/sa-token-plugin/sa-token-context-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/model/SaRequestForDubbo3.java +++ b/sa-token-plugin/sa-token-context-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/model/SaRequestForDubbo3.java @@ -3,6 +3,9 @@ package cn.dev33.satoken.context.dubbo3.model; import cn.dev33.satoken.context.model.SaRequest; import org.apache.dubbo.rpc.RpcContext; +import java.util.List; +import java.util.Map; + /** * Request for Dubbo3 * @@ -41,6 +44,24 @@ public class SaRequestForDubbo3 implements SaRequest { return null; } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + return null; + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + return null; + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-plugin/sa-token-context-grpc/src/main/java/cn/dev33/satoken/context/grpc/model/SaRequestForGrpc.java b/sa-token-plugin/sa-token-context-grpc/src/main/java/cn/dev33/satoken/context/grpc/model/SaRequestForGrpc.java index 269878bd..cbff558f 100644 --- a/sa-token-plugin/sa-token-context-grpc/src/main/java/cn/dev33/satoken/context/grpc/model/SaRequestForGrpc.java +++ b/sa-token-plugin/sa-token-context-grpc/src/main/java/cn/dev33/satoken/context/grpc/model/SaRequestForGrpc.java @@ -3,6 +3,9 @@ package cn.dev33.satoken.context.grpc.model; import cn.dev33.satoken.context.grpc.context.SaTokenGrpcContext; import cn.dev33.satoken.context.model.SaRequest; +import java.util.List; +import java.util.Map; + /** * Request for grpc * @@ -27,6 +30,24 @@ public class SaRequestForGrpc implements SaRequest { return null; } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + return null; + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + return null; + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java index 6ed799ad..40e536d7 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/config/SaSsoConfig.java @@ -61,31 +61,36 @@ public class SaSsoConfig implements Serializable { */ public String authUrl = "/sso/auth"; - /** - * 是否打开单点注销功能 - */ - // public Boolean isSlo = true; // 同Server端 + // /** + // * 是否打开单点注销功能 + // */ + // public Boolean isSlo = true; // 同Server端,不再重复声明 - /** - * 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo) - */ - // public Boolean isHttp = false; // 同Server端 + // /** + // * 是否打开模式三(此值为 true 时将使用 http 请求:校验ticket值、单点注销、获取userinfo) + // */ + // public Boolean isHttp = false; // 同Server端,不再重复声明 - /** - * 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验) - */ - // public String secretkey; // 同Server端 + // /** + // * 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验) + // */ + // public String secretkey; // 同Server端,不再重复声明 /** * 配置 Server 端的 ticket 校验地址 */ public String checkTicketUrl = "/sso/checkTicket"; + /** + * 配置 Server 端查询数据 getData 地址 + */ + public String getDataUrl = "/sso/getData"; + /** * 配置 Server 端查询 userinfo 地址 */ public String userinfoUrl = "/sso/userinfo"; - + /** * 配置 Server 端单点注销地址 */ @@ -97,7 +102,7 @@ public class SaSsoConfig implements Serializable { public String ssoLogoutCall; /** - * 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置 + * 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置 */ public String serverUrl; @@ -240,6 +245,22 @@ public class SaSsoConfig implements Serializable { return this; } + /** + * @return Server 端查询数据 getData 地址 + */ + public String getGetDataUrl() { + return getDataUrl; + } + + /** + * @param getDataUrl 配置 Server 端查询数据 getData 地址 + * @return 对象自身 + */ + public SaSsoConfig setGetDataUrl(String getDataUrl) { + this.getDataUrl = getDataUrl; + return this; + } + /** * @return 配置的 Server 端查询 userinfo 地址 */ @@ -289,14 +310,14 @@ public class SaSsoConfig implements Serializable { } /** - * @return 配置的 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置 + * @return 配置的 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置 */ public String getServerUrl() { return serverUrl; } /** - * @param serverUrl 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置 + * @param serverUrl 配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置 * @return 对象自身 */ public SaSsoConfig setServerUrl(String serverUrl) { @@ -331,6 +352,7 @@ public class SaSsoConfig implements Serializable { + ", client=" + client + ", authUrl=" + authUrl + ", checkTicketUrl=" + checkTicketUrl + + ", getDataUrl=" + getDataUrl + ", userinfoUrl=" + userinfoUrl + ", sloUrl=" + sloUrl + ", ssoLogoutCall=" + ssoLogoutCall @@ -356,6 +378,13 @@ public class SaSsoConfig implements Serializable { return SaFoxUtil.spliceTwoUrl(getServerUrl(), getCheckTicketUrl()); } + /** + * @return 获取拼接url:Server 端查询数据 getData 地址 + */ + public String splicingGetDataUrl() { + return SaFoxUtil.spliceTwoUrl(getServerUrl(), getGetDataUrl()); + } + /** * @return 获取拼接url:Server 端查询 userinfo 地址 */ diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java index d287e5c4..128427f6 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoTemplate.java @@ -1,12 +1,5 @@ package cn.dev33.satoken.sso; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - import cn.dev33.satoken.SaManager; import cn.dev33.satoken.config.SaSsoConfig; import cn.dev33.satoken.context.model.SaRequest; @@ -21,6 +14,8 @@ import cn.dev33.satoken.strategy.SaStrategy; import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaResult; +import java.util.*; + /** * Sa-Token-SSO 单点登录模块 * @author kong @@ -153,7 +148,7 @@ public class SaSsoTemplate { } String loginId = SaManager.getSaTokenDao().get(splicingTicketSaveKey(ticket)); // 如果是 "a,b" 的格式,则只取最前面的一项 - if(loginId != null && loginId.indexOf(",") > -1) { + if(loginId != null && loginId.contains(",")) { String[] arr = loginId.split(","); loginId = arr[0]; } @@ -206,7 +201,7 @@ public class SaSsoTemplate { // 如果是 "a,b" 的格式,则解析出对应的 Client String ticketClient = null; - if(loginId.indexOf(",") > -1) { + if(loginId.contains(",")) { String[] arr = loginId.split(","); loginId = arr[0]; ticketClient = arr[1]; @@ -252,7 +247,7 @@ public class SaSsoTemplate { public void checkRedirectUrl(String url) { // 1、是否是一个有效的url - if(SaFoxUtil.isUrl(url) == false) { + if( ! SaFoxUtil.isUrl(url) ) { throw new SaSsoException("无效redirect:" + url).setCode(SaSsoErrorCode.CODE_30001); } @@ -264,12 +259,11 @@ public class SaSsoTemplate { // 3、是否在[允许地址列表]之中 List authUrlList = Arrays.asList(getAllowUrl().replaceAll(" ", "").split(",")); - if(SaStrategy.me.hasElement.apply(authUrlList, url) == false) { + if( ! SaStrategy.me.hasElement.apply(authUrlList, url) ) { throw new SaSsoException("非法redirect:" + url).setCode(SaSsoErrorCode.CODE_30002); } - // 校验通过 √ - return; + // 校验通过 √ } @@ -285,7 +279,7 @@ public class SaSsoTemplate { return; } SaSession session = getStpLogic().getSessionByLoginId(loginId); - Set urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, ()-> new HashSet()); + Set urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, HashSet::new); urlSet.add(sloCallbackUrl); session.set(SaSsoConsts.SLO_CALLBACK_SET_KEY, urlSet); } @@ -304,7 +298,7 @@ public class SaSsoTemplate { // step.1 遍历通知 Client 端注销会话 SaSsoConfig cfg = SaSsoManager.getConfig(); - Set urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, () -> new HashSet()); + Set urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, HashSet::new); for (String url : urlSet) { url = addSignParams(url, loginId); cfg.getSendHttp().apply(url); @@ -315,12 +309,23 @@ public class SaSsoTemplate { } /** - * 获取:账号资料 - * @param loginId 账号id - * @return 账号资料 + * 根据配置的 getData 地址,查询数据 + * @param paramMap 查询参数 + * @return 查询结果 */ - public Object getUserinfo(Object loginId) { - String url = buildUserinfoUrl(loginId); + public Object getData(Map paramMap) { + String getDataUrl = SaSsoManager.getConfig().splicingGetDataUrl(); + return getData(getDataUrl, paramMap); + } + + /** + * 根据自定义 path 地址,查询数据 (此方法需要配置 sa-token.sso.server-url 地址) + * @param path 自定义 path + * @param paramMap 查询参数 + * @return 查询结果 + */ + public Object getData(String path, Map paramMap) { + String url = buildCustomPathUrl(path, paramMap); return SaSsoManager.getConfig().getSendHttp().apply(url); } @@ -355,17 +360,16 @@ public class SaSsoTemplate { * 部分 Servlet 版本 request.getRequestURL() 返回的 url 带有 query 参数,形如:http://domain.com?id=1, * 如果不加判断会造成最终生成的 serverAuthUrl 带有双 back 参数 ,这个 if 判断正是为了解决此问题 */ - if(clientLoginUrl.indexOf(paramName.back + "=" + back) == -1) { + if( ! clientLoginUrl.contains(paramName.back + "=" + back) ) { clientLoginUrl = SaFoxUtil.joinParam(clientLoginUrl, paramName.back, back); } - String serverAuthUrl = SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl); - + // 返回 - return serverAuthUrl; + return SaFoxUtil.joinParam(serverUrl, paramName.redirect, clientLoginUrl); } /** - * 构建URL:Server端向Client下放ticke的地址 + * 构建URL:Server端向Client下放ticket的地址 * @param loginId 账号id * @param client 客户端标识 * @param redirect Client端提供的重定向地址 @@ -412,16 +416,6 @@ public class SaSsoTemplate { return url; } - /** - * 构建URL:Server端 账号资料查询地址 - * @param loginId 账号id - * @return Server端 账号资料查询地址 - */ - public String buildUserinfoUrl(Object loginId) { - String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl(); - return addSignParams(userinfoUrl, loginId); - } - /** * 构建URL:校验ticket的URL *

在模式三下,Client端拿到Ticket后根据此地址向Server端发送请求,获取账号id @@ -461,6 +455,34 @@ public class SaSsoTemplate { return addSignParams(url, loginId); } + /** + * 构建URL:Server端 getData 地址,带签名等参数 + * @param paramMap 查询参数 + * @return / + */ + public String buildGetDataUrl(Map paramMap) { + String getDataUrl = SaSsoManager.getConfig().getGetDataUrl(); + return buildCustomPathUrl(getDataUrl, paramMap); + } + + /** + * 构建URL:Server 端自定义 path 地址,带签名等参数 (此方法需要配置 sa-token.sso.server-url 地址) + * @param paramMap 请求参数 + * @return / + */ + public String buildCustomPathUrl(String path, Map paramMap) { + // 如果path不是以 http 开头,那么就拼接上 serverUrl + String url = path; + if( ! url.startsWith("http") ) { + String serverUrl = SaSsoManager.getConfig().getServerUrl(); + SaSsoException.throwByNull(serverUrl, "请先配置 sa-token.sso.server-url 地址", SaSsoErrorCode.CODE_30012); + url = SaFoxUtil.spliceTwoUrl(serverUrl, path); + } + + // 添加签名等参数,并序列化 + return addSignParams(url, paramMap); + } + // ------------------- 返回相应key ------------------- @@ -510,24 +532,65 @@ public class SaSsoTemplate { } /** - * 校验secretkey秘钥是否有效 (API已过期,请更改为更安全的 sign 式校验) - * @param secretkey 秘钥 + * 给 paramMap 追加 sign 等参数,并序列化为kv字符串,拼接到url后面 + * @param url 请求地址 + * @param paramMap 请求原始参数列表 + * @return 加工后的url */ - @Deprecated - public void checkSecretkey(String secretkey) { - if(SaFoxUtil.isEmpty(secretkey) || secretkey.equals(getSecretkey()) == false) { - throw new SaSsoException("无效秘钥:" + secretkey).setCode(SaSsoErrorCode.CODE_30003); - } + public String addSignParams(String url, Map paramMap) { + // 追加:时间戳、随机字符串、参数签名 + SaManager.getSaSignTemplate().addSignParams(paramMap, getSecretkey()); + + // 序列化为kv字符串 + String signParams = SaManager.getSaSignTemplate().joinParams(paramMap); + + // 拼接到一起 + return SaFoxUtil.joinParam(url, signParams); } - + /** - * 根据参数计算签名 + * 给 url 拼接 loginId 参数,并拼接 sign 等参数 + * @param url 链接 + * @param loginId 账号id + * @return 加工后的url + */ + public String addSignParams(String url, Object loginId) { + Map paramMap = new LinkedHashMap<>(); + paramMap.put(paramName.loginId, loginId); + return addSignParams(url, paramMap); + } + + /** + * 校验签名 + * @param req request + */ + public void checkSign(SaRequest req) { + // 获取签名、时间戳、随机字符串 + String sign = req.getParamNotNull(paramName.sign); + String timestamp = req.getParamNotNull(paramName.timestamp); + String nonce = req.getParamNotNull(paramName.nonce); + + // 1、校验时间戳 + SaManager.getSaSignTemplate().checkTimestamp(Long.parseLong(timestamp), SaSsoManager.getConfig().getTimestampDisparity()); + + // 2、校验随机字符串 + + // 3、校验签名 + SaManager.getSaSignTemplate().checkSign(req.getParamMap(), getSecretkey(), sign); + } + + + // -------- 以下方法已废弃,仅为兼容旧版本而保留 -------- + + /** + * 根据参数计算签名 * @param loginId 账号id * @param timestamp 当前时间戳,13位 - * @param nonce 随机字符串 + * @param nonce 随机字符串 * @param secretkey 账号id - * @return 签名 + * @return 签名 */ + @Deprecated public String getSign(Object loginId, String timestamp, String nonce, String secretkey) { Map map = new TreeMap<>(); map.put(paramName.loginId, loginId); @@ -537,58 +600,26 @@ public class SaSsoTemplate { } /** - * 给 url 追加 sign 等参数 - * @param url 连接 - * @param loginId 账号id - * @return 加工后的url + * 构建URL:Server端 账号资料查询地址 + * @param loginId 账号id + * @return Server端 账号资料查询地址 */ - public String addSignParams(String url, Object loginId) { - - // 时间戳、随机字符串、参数签名 - String timestamp = String.valueOf(System.currentTimeMillis()); - String nonce = SaFoxUtil.getRandomString(20); - String sign = getSign(loginId, timestamp, nonce, getSecretkey()); - - // 追加到url - url = SaFoxUtil.joinParam(url, paramName.loginId, loginId); - url = SaFoxUtil.joinParam(url, paramName.timestamp, timestamp); - url = SaFoxUtil.joinParam(url, paramName.nonce, nonce); - url = SaFoxUtil.joinParam(url, paramName.sign, sign); - return url; + @Deprecated + public String buildUserinfoUrl(Object loginId) { + String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl(); + return addSignParams(userinfoUrl, loginId); } /** - * 校验签名 - * @param req request + * 获取:账号资料 + * @param loginId 账号id + * @return 账号资料 */ - public void checkSign(SaRequest req) { - - // 参数签名、账号id、时间戳、随机字符串 - String sign = req.getParamNotNull(paramName.sign); - String loginId = req.getParamNotNull(paramName.loginId); - String timestamp = req.getParamNotNull(paramName.timestamp); - String nonce = req.getParamNotNull(paramName.nonce); - - // 校验时间戳 - checkTimestamp(Long.valueOf(timestamp)); - - // 校验签名 - String calcSign = getSign(loginId, timestamp, nonce, getSecretkey()); - if(calcSign.equals(sign) == false) { - throw new SaSsoException("签名无效:" + calcSign).setCode(SaSsoErrorCode.CODE_30008); - } + @Deprecated + public Object getUserinfo(Object loginId) { + String url = buildUserinfoUrl(loginId); + return SaSsoManager.getConfig().getSendHttp().apply(url); } - /** - * 校验时间戳与当前时间的差距是否超出限制 - * @param timestamp 时间戳 - */ - public void checkTimestamp(long timestamp) { - long disparity = Math.abs(System.currentTimeMillis() - timestamp); - long allowDisparity = SaSsoManager.getConfig().getTimestampDisparity(); - if(allowDisparity != -1 && disparity > allowDisparity) { - throw new SaSsoException("timestamp 超出允许的范围").setCode(SaSsoErrorCode.CODE_30007); - } - } - + } diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java index 60f875b9..4388c043 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoUtil.java @@ -3,6 +3,8 @@ package cn.dev33.satoken.sso; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.util.SaResult; +import java.util.Map; + /** * Sa-Token-SSO 单点登录模块 工具类 * @author kong @@ -139,12 +141,22 @@ public class SaSsoUtil { } /** - * 获取:账号资料 - * @param loginId 账号id - * @return 账号资料 + * 获取:查询数据 + * @param paramMap 查询参数 + * @return 查询结果 */ - public static Object getUserinfo(Object loginId) { - return ssoTemplate.getUserinfo(loginId); + public static Object getData(Map paramMap) { + return ssoTemplate.getData(paramMap); + } + + /** + * 根据自定义 path 查询数据 (此方法需要配置 sa-token.sso.server-url 地址) + * @param path 自定义 path + * @param paramMap 查询参数 + * @return 查询结果 + */ + public static Object getData(String path, Map paramMap) { + return ssoTemplate.getData(path, paramMap); } @@ -161,7 +173,7 @@ public class SaSsoUtil { } /** - * 构建URL:Server端向Client下放ticke的地址 + * 构建URL:Server端向Client下放ticket的地址 * @param loginId 账号id * @param client 客户端标识 * @param redirect Client端提供的重定向地址 @@ -172,14 +184,23 @@ public class SaSsoUtil { } /** - * 构建URL:Server端 账号资料查询地址 - * @param loginId 账号id - * @return Server端 账号资料查询地址 + * 构建URL:Server端 getData 地址,带签名等参数 + * @param paramMap 查询参数 + * @return / */ - public static String buildUserinfoUrl(Object loginId) { - return ssoTemplate.buildUserinfoUrl(loginId); + public static String buildGetDataUrl(Map paramMap) { + return ssoTemplate.buildGetDataUrl(paramMap); } - + + /** + * 构建URL:Server 端自定义 path 地址,带签名等参数 (此方法需要配置 sa-token.sso.server-url 地址) + * @param paramMap 请求参数 + * @return / + */ + public static String buildCustomPathUrl(String path, Map paramMap) { + return ssoTemplate.buildCustomPathUrl(path, paramMap); + } + // ------------------- 请求相关 ------------------- @@ -193,31 +214,20 @@ public class SaSsoUtil { } /** - * 校验secretkey秘钥是否有效 (API已过期,请更改为更安全的 sign 式校验) - * @param secretkey 秘钥 + * 给 paramMap 追加 sign 等参数,并序列化为kv字符串,拼接到url后面 + * @param url 请求地址 + * @param paramMap 请求原始参数列表 + * @return 加工后的url */ - @Deprecated - public static void checkSecretkey(String secretkey) { - ssoTemplate.checkSecretkey(secretkey); + public static String addSignParams(String url, Map paramMap) { + return ssoTemplate.addSignParams(url, paramMap); } /** - * 根据参数计算签名 + * 给 url 拼接 loginId 参数,并拼接 sign 等参数 + * @param url 链接 * @param loginId 账号id - * @param timestamp 当前时间戳,13位 - * @param nonce 随机字符串 - * @param secretkey 账号id - * @return 签名 - */ - public static String getSign(Object loginId, String timestamp, String nonce, String secretkey) { - return ssoTemplate.getSign(loginId, timestamp, nonce, secretkey); - } - - /** - * 给 url 追加 sign 等参数 - * @param url 连接 - * @param loginId 账号id - * @return 加工后的url + * @return 加工后的url */ public static String addSignParams(String url, Object loginId) { return ssoTemplate.addSignParams(url, loginId); @@ -231,12 +241,40 @@ public class SaSsoUtil { ssoTemplate.checkSign(req); } + + // -------- 以下方法已废弃,仅为兼容旧版本而保留 -------- + /** - * 校验时间戳与当前时间的差距是否超出限制 - * @param timestamp 时间戳 + * 根据参数计算签名 + * @param loginId 账号id + * @param timestamp 当前时间戳,13位 + * @param nonce 随机字符串 + * @param secretkey 账号id + * @return 签名 */ - public static void checkTimestamp(long timestamp) { - ssoTemplate.checkTimestamp(timestamp); + @Deprecated + public static String getSign(Object loginId, String timestamp, String nonce, String secretkey) { + return ssoTemplate.getSign(loginId, timestamp, nonce, secretkey); } - + + /** + * 获取:账号资料 + * @param loginId 账号id + * @return 账号资料 + */ + @Deprecated + public static Object getUserinfo(Object loginId) { + return ssoTemplate.getUserinfo(loginId); + } + + /** + * 构建URL:Server端 账号资料查询地址 + * @param loginId 账号id + * @return Server端 账号资料查询地址 + */ + @Deprecated + public static String buildUserinfoUrl(Object loginId) { + return ssoTemplate.buildUserinfoUrl(loginId); + } + } diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/error/SaSsoErrorCode.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/error/SaSsoErrorCode.java index ce2eedb7..0763086f 100644 --- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/error/SaSsoErrorCode.java +++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/error/SaSsoErrorCode.java @@ -40,5 +40,8 @@ public interface SaSsoErrorCode { /** 该 ticket 不属于当前 client */ public static final int CODE_30011 = 30011; - + + /** 当前缺少配置 server-url 地址 */ + public static final int CODE_30012 = 30012; + } diff --git a/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java b/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java index 77d2e102..434ac1ee 100644 --- a/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java +++ b/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java @@ -1,7 +1,5 @@ package cn.dev33.satoken.servlet.model; -import java.io.IOException; - import cn.dev33.satoken.SaManager; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.exception.SaTokenException; @@ -12,6 +10,9 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; + /** * Request for Jakarta Servlet * @author kong @@ -48,6 +49,36 @@ public class SaRequestForServlet implements SaRequest { return request.getParameter(name); } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + Enumeration parameterNames = request.getParameterNames(); + List list = new ArrayList<>(); + while (parameterNames.hasMoreElements()) { + list.add(parameterNames.nextElement()); + } + return list; + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + // 获取所有参数 + Map parameterMap = request.getParameterMap(); + Map map = new LinkedHashMap<>(parameterMap.size()); + for (String key : parameterMap.keySet()) { + String[] values = parameterMap.get(key); + map.put(key, values[0]); + } + return map; + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java index da98532e..35e58005 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java @@ -12,6 +12,8 @@ import cn.dev33.satoken.reactor.context.SaReactorHolder; import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; import cn.dev33.satoken.util.SaFoxUtil; +import java.util.*; + /** * Request for Reactor * @author kong @@ -48,6 +50,25 @@ public class SaRequestForReactor implements SaRequest { return request.getQueryParams().getFirst(name); } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + Set names = request.getQueryParams().keySet(); + return new ArrayList<>(names); + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + return request.getQueryParams().toSingleValueMap(); + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java index da98532e..da8819c0 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java +++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java @@ -12,6 +12,11 @@ import cn.dev33.satoken.reactor.context.SaReactorHolder; import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; import cn.dev33.satoken.util.SaFoxUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * Request for Reactor * @author kong @@ -48,6 +53,25 @@ public class SaRequestForReactor implements SaRequest { return request.getQueryParams().getFirst(name); } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + Set names = request.getQueryParams().keySet(); + return new ArrayList<>(names); + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + return request.getQueryParams().toSingleValueMap(); + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java index 374bd25a..46b457c8 100644 --- a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java +++ b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java @@ -1,6 +1,7 @@ package cn.dev33.satoken.servlet.model; import java.io.IOException; +import java.util.*; import javax.servlet.ServletException; import javax.servlet.http.Cookie; @@ -49,6 +50,36 @@ public class SaRequestForServlet implements SaRequest { return request.getParameter(name); } + /** + * 获取 [请求体] 里提交的所有参数名称 + * @return 参数名称列表 + */ + @Override + public List getParamNames(){ + Enumeration parameterNames = request.getParameterNames(); + List list = new ArrayList<>(); + while (parameterNames.hasMoreElements()) { + list.add(parameterNames.nextElement()); + } + return list; + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + // 获取所有参数 + Map parameterMap = request.getParameterMap(); + Map map = new LinkedHashMap<>(parameterMap.size()); + for (String key : parameterMap.keySet()) { + String[] values = parameterMap.get(key); + map.put(key, values[0]); + } + return map; + } + /** * 在 [请求头] 里获取一个值 */ diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java index ae66fd12..7cf25fb1 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java @@ -5,6 +5,11 @@ import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.util.SaFoxUtil; import org.noear.solon.core.handle.Context; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * @author noear * @since 1.4 @@ -27,6 +32,21 @@ public class SaRequestForSolon implements SaRequest { return ctx.param(s); } + @Override + public List getParamNames(){ + Set names = ctx.paramMap().keySet(); + return new ArrayList<>(names); + } + + /** + * 获取 [请求体] 里提交的所有参数 + * @return 参数列表 + */ + @Override + public Map getParamMap(){ + return ctx.paramMap(); + } + @Override public String getHeader(String s) { return ctx.header(s);