From ac09cced2b46349d75af41e0bcc02be9b26ee74a Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Wed, 3 May 2023 04:23:48 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9AAPI=20=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3=E7=AD=BE=E5=90=8D=E6=89=80=E6=9C=89=E6=96=B9=E6=B3=95?=
=?UTF-8?q?=E5=9D=87=E8=BF=81=E7=A7=BB=E8=87=B3=20core=20=E6=A0=B8?=
=?UTF-8?q?=E5=BF=83=E6=A8=A1=E5=9D=97=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/cn/dev33/satoken/SaManager.java | 9 +-
.../cn/dev33/satoken/config/SaSignConfig.java | 111 +++++++
.../dev33/satoken/config/SaTokenConfig.java | 32 +-
.../satoken/exception/SaSignException.java | 48 +++
.../cn/dev33/satoken/sign/SaSignTemplate.java | 279 ++++++++++++++----
.../sign/SaSignTemplateDefaultImpl.java | 11 -
.../cn/dev33/satoken/sign/SaSignUtil.java | 159 ++++++++++
.../java/com/pj/sso/SsoServerController.java | 6 +-
.../src/main/resources/application.yml | 14 +-
.../java/com/pj/sso/SsoClientController.java | 16 +-
.../src/main/resources/application.yml | 9 +-
sa-token-doc/sso/sso-questions.md | 7 +
sa-token-doc/sso/sso-server.md | 21 +-
sa-token-doc/sso/sso-type2.md | 4 -
sa-token-doc/sso/sso-type3.md | 15 +-
.../cn/dev33/satoken/config/SaSsoConfig.java | 54 +---
.../cn/dev33/satoken/sso/SaSsoProcessor.java | 4 +-
.../cn/dev33/satoken/sso/SaSsoTemplate.java | 123 +++-----
.../java/cn/dev33/satoken/sso/SaSsoUtil.java | 40 +--
19 files changed, 661 insertions(+), 301 deletions(-)
create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/config/SaSignConfig.java
create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/exception/SaSignException.java
delete mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplateDefaultImpl.java
create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignUtil.java
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
index ce6f24fd..8e0d108b 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java
@@ -1,8 +1,5 @@
package cn.dev33.satoken;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.context.SaTokenContext;
@@ -19,7 +16,6 @@ import cn.dev33.satoken.log.SaLog;
import cn.dev33.satoken.log.SaLogForConsole;
import cn.dev33.satoken.same.SaSameTemplate;
import cn.dev33.satoken.sign.SaSignTemplate;
-import cn.dev33.satoken.sign.SaSignTemplateDefaultImpl;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
import cn.dev33.satoken.stp.StpLogic;
@@ -28,6 +24,9 @@ import cn.dev33.satoken.temp.SaTempDefaultImpl;
import cn.dev33.satoken.temp.SaTempInterface;
import cn.dev33.satoken.util.SaFoxUtil;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
/**
* 管理 Sa-Token 所有全局组件
* @author kong
@@ -209,7 +208,7 @@ public class SaManager {
if (saSignTemplate == null) {
synchronized (SaManager.class) {
if (saSignTemplate == null) {
- SaManager.saSignTemplate = new SaSignTemplateDefaultImpl();
+ SaManager.saSignTemplate = new SaSignTemplate();
}
}
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSignConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSignConfig.java
new file mode 100644
index 00000000..90ca38d2
--- /dev/null
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaSignConfig.java
@@ -0,0 +1,111 @@
+package cn.dev33.satoken.config;
+
+/**
+ * Sa-Token API 接口签名/验签 相关配置类
+ *
+ * @author click33
+ * @since 2023/5/2
+ */
+public class SaSignConfig {
+
+ /**
+ * API 调用签名秘钥
+ */
+ private String secretKey;
+
+ /**
+ * 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距,默认15分钟
+ */
+ private long timestampDisparity = 1000 * 60 * 15;
+
+ /**
+ * 是否校验 nonce 随机字符串
+ */
+ private Boolean isCheckNonce = true;
+
+
+ /**
+ * 获取 API 调用签名秘钥
+ *
+ * @return /
+ */
+ public String getSecretKey() {
+ return this.secretKey;
+ }
+
+ /**
+ * 设置 API 调用签名秘钥
+ *
+ * @param secretKey /
+ * @return 对象自身
+ */
+ public SaSignConfig setSecretKey(String secretKey) {
+ this.secretKey = secretKey;
+ return this;
+ }
+
+ /**
+ * 获取 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距,默认15分钟
+ *
+ * @return /
+ */
+ public long getTimestampDisparity() {
+ return this.timestampDisparity;
+ }
+
+ /**
+ * 设置 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距,默认15分钟
+ *
+ * @param timestampDisparity /
+ * @return 对象自身
+ */
+ public SaSignConfig setTimestampDisparity(long timestampDisparity) {
+ this.timestampDisparity = timestampDisparity;
+ return this;
+ }
+
+ /**
+ * 获取 是否校验 nonce 随机字符串
+ *
+ * @return /
+ */
+ public Boolean getIsCheckNonce() {
+ return this.isCheckNonce;
+ }
+
+ /**
+ * 设置 是否校验 nonce 随机字符串
+ *
+ * @param isCheckNonce /
+ * @return 对象自身
+ */
+ public SaSignConfig setIsCheckNonce(Boolean isCheckNonce) {
+ this.isCheckNonce = isCheckNonce;
+ return this;
+ }
+
+ /**
+ * 计算保存 nonce 时应该使用的 ttl,单位:秒
+ * @return /
+ */
+ public long getSaveNonceExpire() {
+ // 如果 timestampDisparity >= 0,则 nonceTtl 的值等于 timestampDisparity 的值,单位转秒
+ if(timestampDisparity >= 0) {
+ return timestampDisparity / 1000;
+ }
+ // 否则,nonceTtl 的值为 24 小时
+ else {
+ return 60 * 60 * 24;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SaSignConfig ["
+ + "secretKey=" + secretKey
+ + ", timestampDisparity=" + timestampDisparity
+ + ", isCheckNonce=" + isCheckNonce
+ + "]";
+ }
+
+}
\ No newline at end of file
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java
index e0ff46f9..5e82d7c4 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java
@@ -1,9 +1,9 @@
package cn.dev33.satoken.config;
-import java.io.Serializable;
-
import cn.dev33.satoken.util.SaFoxUtil;
+import java.io.Serializable;
+
/**
* Sa-Token 配置类 Model
*
@@ -109,7 +109,12 @@ public class SaTokenConfig implements Serializable {
* Cookie配置对象
*/
public SaCookieConfig cookie = new SaCookieConfig();
-
+
+ /**
+ * API 签名配置对象
+ */
+ public SaSignConfig sign = new SaSignConfig();
+
/**
* @return token名称 (同时也是cookie名称)
@@ -532,7 +537,23 @@ public class SaTokenConfig implements Serializable {
this.cookie = cookie;
return this;
}
-
+
+ /**
+ * @return API 签名全局配置对象
+ */
+ public SaSignConfig getSign() {
+ return sign;
+ }
+
+ /**
+ * @param sign API 签名全局配置对象
+ * @return 对象自身
+ */
+ public SaTokenConfig setSign(SaSignConfig sign) {
+ this.sign = sign;
+ return this;
+ }
+
@Override
public String toString() {
return "SaTokenConfig ["
@@ -561,7 +582,8 @@ public class SaTokenConfig implements Serializable {
+ ", currDomain=" + currDomain
+ ", sameTokenTimeout=" + sameTokenTimeout
+ ", checkSameToken=" + checkSameToken
- + ", cookie=" + cookie
+ + ", cookie=" + cookie
+ + ", sign=" + sign
+ "]";
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/exception/SaSignException.java b/sa-token-core/src/main/java/cn/dev33/satoken/exception/SaSignException.java
new file mode 100644
index 00000000..491bed46
--- /dev/null
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/exception/SaSignException.java
@@ -0,0 +1,48 @@
+package cn.dev33.satoken.exception;
+
+import cn.dev33.satoken.util.SaFoxUtil;
+
+/**
+ * 一个异常:代表 API 参数签名校验失败
+ *
+ * @author kong
+ * @since 2023-5-3
+ */
+public class SaSignException extends SaTokenException {
+
+ /**
+ * 序列化版本号
+ */
+ private static final long serialVersionUID = 6806129545290130144L;
+
+ /**
+ * 一个异常:代表 API 参数签名校验失败
+ * @param message 异常描述
+ */
+ public SaSignException(String message) {
+ super(message);
+ }
+
+ /**
+ * 如果flag==true,则抛出message异常
+ * @param flag 标记
+ * @param message 异常信息
+ */
+ public static void throwBy(boolean flag, String message) {
+ if(flag) {
+ throw new SaSignException(message);
+ }
+ }
+
+ /**
+ * 如果 value isEmpty,则抛出 message 异常
+ * @param value 值
+ * @param message 异常信息
+ */
+ public static void throwByNull(Object value, String message) {
+ if(SaFoxUtil.isEmpty(value)) {
+ throw new SaSignException(message);
+ }
+ }
+
+}
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 346e8773..c9057058 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,7 +1,10 @@
package cn.dev33.satoken.sign;
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.config.SaSignConfig;
+import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.error.SaErrorCode;
-import cn.dev33.satoken.exception.SaTokenException;
+import cn.dev33.satoken.exception.SaSignException;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.util.SaFoxUtil;
@@ -9,19 +12,74 @@ import java.util.Map;
import java.util.TreeMap;
/**
- * 参数签名算法
+ * API 参数签名算法
*
* @author kong
* @since 2022-4-27
*/
-public interface SaSignTemplate {
+public class SaSignTemplate {
+
+ // ----------- 签名配置
+
+ SaSignConfig signConfig;
+
+ /**
+ * 获取:API 签名配置
+ * @return /
+ */
+ public SaSignConfig getSignConfig() {
+ return signConfig;
+ }
+
+ /**
+ * 获取:API 签名配置:
+ * 1. 如果用户自定义了 signConfig ,则使用用户自定义的。
+ * 2. 否则使用全局默认配置。
+ * @return /
+ */
+ public SaSignConfig getSignConfigOrGlobal() {
+ // 如果用户自定义了 signConfig ,则使用用户自定义的
+ if(signConfig != null) {
+ return signConfig;
+ }
+ // 否则使用全局默认配置
+ return SaManager.getConfig().getSign();
+ }
+
+ /**
+ * 获取:API 签名配置的秘钥
+ * @return /
+ */
+ public String getSecretKey() {
+ return getSignConfigOrGlobal().getSecretKey();
+ }
+
+ /**
+ * 设置:API 签名配置
+ * @param signConfig /
+ */
+ public SaSignTemplate setSignConfig(SaSignConfig signConfig) {
+ this.signConfig = signConfig;
+ return this;
+ }
+
+
+ // ----------- 自定义使用的参数名称 (不声明final,允许开发者自定义修改)
+
+ public static String key = "key";
+ public static String timestamp = "timestamp";
+ public static String nonce = "nonce";
+ public static String sign = "sign";
+
+
+ // ----------- 拼接参数
/**
* 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
* @param paramsMap 参数列表
* @return 拼接出的参数字符串
*/
- public default String joinParams(Map paramsMap) {
+ public String joinParams(Map paramsMap) {
// 按照 k1=v1&k2=v2&k3=v3 排列
StringBuilder sb = new StringBuilder();
@@ -46,7 +104,7 @@ public interface SaSignTemplate {
* @param paramsMap 参数列表
* @return 拼接出的参数字符串
*/
- public default String joinParamsDictSort(Map paramsMap) {
+ public String joinParamsDictSort(Map paramsMap) {
// 保证字段按照字典顺序排列
if( ! (paramsMap instanceof TreeMap) ) {
paramsMap = new TreeMap<>(paramsMap);
@@ -56,62 +114,40 @@ public interface SaSignTemplate {
return joinParams(paramsMap);
}
+
+ // ----------- 创建签名
+
/**
* 创建签名:md5(paramsStr + keyStr)
- * @param paramsMap 参数列表
- * @param key 秘钥
+ * @param paramsMap 参数列表
* @return 签名
*/
- public default String createSign(Map paramsMap, String key) {
- SaTokenException.throwByNull(key, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
+ public String createSign(Map paramsMap) {
+ String secretKey = getSecretKey();
+ SaSignException.throwByNull(secretKey, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
// 如果调用者不小心传入了 sign 参数,则此处需要将 sign 参数排除在外
- // 为了保证不影响原有的 paramsMap,此处需要再复制一份
- if(paramsMap.containsKey("sign")) {
+ if(paramsMap.containsKey(sign)) {
+ // 为了保证不影响原有的 paramsMap,此处需要再复制一份
paramsMap = new TreeMap<>(paramsMap);
- paramsMap.remove("sign");
+ paramsMap.remove(sign);
}
// 计算签名
String paramsStr = joinParamsDictSort(paramsMap);
- String fullStr = paramsStr + "&key=" + key;
+ String fullStr = paramsStr + "&" + key + "=" + secretKey;
return SaSecureUtil.md5(fullStr);
}
- /**
- * 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
- * @param paramsMap 参数列表
- * @param key 秘钥
- * @param sign 待验证的签名
- * @return 签名是否有效
- */
- public default boolean isValidSign(Map paramsMap, String key, String sign) {
- String theSign = createSign(paramsMap, key);
- return theSign.equals(sign);
- }
-
- /**
- * 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
- * @param paramsMap 参数列表
- * @param key 秘钥
- * @param sign 待验证的签名
- */
- public default void checkSign(Map paramsMap, String key, String sign) {
- if( ! isValidSign(paramsMap, key, sign) ) {
- throw new SaTokenException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202);
- }
- }
-
/**
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数
- * @param paramsMap 参数列表
- * @param key 秘钥
+ * @param paramsMap 参数列表
* @return 加工后的参数列表
*/
- public default Map addSignParams(Map paramsMap, String key) {
- paramsMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
- paramsMap.put("nonce", SaFoxUtil.getRandomString(32));
- paramsMap.put("sign", createSign(paramsMap, key));
+ public Map addSignParams(Map paramsMap) {
+ paramsMap.put(timestamp, String.valueOf(System.currentTimeMillis()));
+ paramsMap.put(nonce, SaFoxUtil.getRandomString(32));
+ paramsMap.put(sign, createSign(paramsMap));
return paramsMap;
}
@@ -119,24 +155,26 @@ public interface SaSignTemplate {
* 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
* data=xxx8nonce=xxx8timestamp=xxx8sign=xxx
* @param paramsMap 参数列表
- * @param key 秘钥
* @return 加工后的参数列表 转化为的参数字符串
*/
- public default String addSignParamsAndToString(Map paramsMap, String key) {
+ public String addSignParamsAndJoin(Map paramsMap) {
// 追加参数
- paramsMap = addSignParams(paramsMap, key);
+ paramsMap = addSignParams(paramsMap);
- // .
+ // 拼接参数
return joinParams(paramsMap);
}
+
+ // ----------- 校验签名
+
/**
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
* @param timestamp 待校验的时间戳
- * @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制
* @return 是否在允许的范围内
*/
- public default boolean isValidTimestamp(long timestamp, long allowDisparity) {
+ public boolean isValidTimestamp(long timestamp) {
+ long allowDisparity = getSignConfigOrGlobal().getTimestampDisparity();
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
return allowDisparity == -1 || disparity <= allowDisparity;
}
@@ -144,29 +182,142 @@ public interface SaSignTemplate {
/**
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
* @param timestamp 待校验的时间戳
- * @param allowDisparity 允许的最大时间差(单位:ms),-1 代表不限制
*/
- public default void checkTimestamp(long timestamp, long allowDisparity) {
- if( ! isValidTimestamp(timestamp, allowDisparity) ) {
- throw new SaTokenException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203);
+ public void checkTimestamp(long timestamp) {
+ if( ! isValidTimestamp(timestamp) ) {
+ throw new SaSignException("timestamp 超出允许的范围:" + timestamp).setCode(SaErrorCode.CODE_12203);
}
}
- // ------------------ 以下为兼容旧版本的方法 ------------------
+ /**
+ * 判断:随机字符串 nonce 是否有效。
+ * 注意:同一 nonce 可以被多次判断有效,不会被缓存
+ * @param nonce 待判断的随机字符串
+ * @return 是否有效
+ */
+ public boolean isValidNonce(String nonce) {
+ // 为空代表无效
+ if(SaFoxUtil.isEmpty(nonce)) {
+ return false;
+ }
+
+ // 校验此 nonce 是否已被使用过
+ String key = splicingNonceSaveKey(nonce);
+ return SaManager.getSaTokenDao().get(key) == null;
+ }
/**
- * 请更换为 addSignParamsAndToString
- * @param paramsMap 参数列表
- * @param key 秘钥
- * @return 加工后的参数列表 转化为的参数字符串
+ * 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
+ * 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
+ * @param nonce 待校验的随机字符串
*/
- @Deprecated
- public default String addSignParamsToString(Map paramsMap, String key) {
- // 追加参数
- paramsMap = addSignParams(paramsMap, key);
+ public void checkNonce(String nonce) {
+ // 为空代表无效
+ if(SaFoxUtil.isEmpty(nonce)) {
+ throw new SaSignException("nonce 为空,无效");
+ }
- // .
- return joinParams(paramsMap);
+ // 校验此 nonce 是否已被使用过
+ String key = splicingNonceSaveKey(nonce);
+ if(SaManager.getSaTokenDao().get(key) != null) {
+ throw new SaSignException("此 nonce 已被使用过,不可重复使用:" + nonce);
+ }
+
+ // 校验通过后,将此 nonce 保存在缓存中,保证下次校验无法通过
+ SaManager.getSaTokenDao().set(key, nonce, getSignConfigOrGlobal().getSaveNonceExpire());
+ }
+
+ /**
+ * 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
+ * @param paramsMap 参数列表
+ * @param sign 待验证的签名
+ * @return 签名是否有效
+ */
+ public boolean isValidSign(Map paramsMap, String sign) {
+ String theSign = createSign(paramsMap);
+ return theSign.equals(sign);
+ }
+
+ /**
+ * 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
+ * @param paramsMap 参数列表
+ * @param sign 待验证的签名
+ */
+ public void checkSign(Map paramsMap, String sign) {
+ if( ! isValidSign(paramsMap, sign) ) {
+ throw new SaSignException("无效签名:" + sign).setCode(SaErrorCode.CODE_12202);
+ }
+ }
+
+ /**
+ * 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
+ * @param paramMap 待校验的请求参数集合
+ * @return 是否合法
+ */
+ public boolean isValidParamMap(Map paramMap) {
+ // 获取必须的三个参数
+ String timestampValue = paramMap.get(timestamp);
+ String nonceValue = paramMap.get(nonce);
+ String signValue = paramMap.get(sign);
+
+ // 三个参数必须全部非空
+ SaSignException.throwByNull(timestampValue, "缺少 timestamp 字段");
+ SaSignException.throwByNull(nonceValue, "缺少 nonce 字段");
+ SaSignException.throwByNull(signValue, "缺少 sign 字段");
+
+ // 三个值的校验必须全部通过
+ return isValidTimestamp(Long.parseLong(timestampValue))
+ && (getSignConfigOrGlobal().getIsCheckNonce() ? isValidNonce(nonceValue) : true)
+ && isValidSign(paramMap, signValue);
+ }
+
+ /**
+ * 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
+ * @param paramMap 待校验的请求参数集合
+ */
+ public void checkParamMap(Map paramMap) {
+ // 获取必须的三个参数
+ String timestampValue = paramMap.get(timestamp);
+ String nonceValue = paramMap.get(nonce);
+ String signValue = paramMap.get(sign);
+
+ // 依次校验三个参数
+ checkTimestamp(Long.parseLong(timestampValue));
+ if(getSignConfigOrGlobal().getIsCheckNonce()) {
+ checkNonce(nonceValue);
+ }
+ checkSign(paramMap, signValue);
+
+ // 通过 √
+ }
+
+ /**
+ * 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
+ * @param request 待校验的请求对象
+ * @return 是否合法
+ */
+ public boolean isValidRequest(SaRequest request) {
+ return isValidParamMap(request.getParamMap());
+ }
+
+ /**
+ * 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
+ * @param request 待校验的请求对象
+ */
+ public void checkRequest(SaRequest request) {
+ checkParamMap(request.getParamMap());
+ }
+
+
+ // ------------------- 返回相应key -------------------
+
+ /**
+ * 拼接key:存储 nonce 时使用的 key
+ * @param nonce nonce 值
+ * @return key
+ */
+ public String splicingNonceSaveKey(String nonce) {
+ return SaManager.getConfig().getTokenName() + ":sign:nonce:" + nonce;
}
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplateDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplateDefaultImpl.java
deleted file mode 100644
index f8137033..00000000
--- a/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignTemplateDefaultImpl.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package cn.dev33.satoken.sign;
-
-/**
- * 参数签名算法 [默认实现类]
- *
- * @author kong
- * @since: 2022-4-27
- */
-public class SaSignTemplateDefaultImpl implements SaSignTemplate {
-
-}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignUtil.java
new file mode 100644
index 00000000..649b9b2c
--- /dev/null
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/sign/SaSignUtil.java
@@ -0,0 +1,159 @@
+package cn.dev33.satoken.sign;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.context.model.SaRequest;
+
+import java.util.Map;
+
+/**
+ * API 参数签名算法 - 工具类
+ *
+ * @author kong
+ * @since 2022-4-27
+ */
+public class SaSignUtil {
+
+ // ----------- 拼接参数
+
+ /**
+ * 将所有参数连接成一个字符串(不排序),形如:b=28a=18c=3
+ * @param paramsMap 参数列表
+ * @return 拼接出的参数字符串
+ */
+ public static String joinParams(Map paramsMap) {
+ return SaManager.getSaSignTemplate().joinParams(paramsMap);
+ }
+
+ /**
+ * 将所有参数按照字典顺序连接成一个字符串,形如:a=18b=28c=3
+ * @param paramsMap 参数列表
+ * @return 拼接出的参数字符串
+ */
+ public static String joinParamsDictSort(Map paramsMap) {
+ return SaManager.getSaSignTemplate().joinParamsDictSort(paramsMap);
+ }
+
+
+ // ----------- 创建签名
+
+ /**
+ * 创建签名:md5(paramsStr + keyStr)
+ * @param paramsMap 参数列表
+ * @return 签名
+ */
+ public static String createSign(Map paramsMap) {
+ return SaManager.getSaSignTemplate().createSign(paramsMap);
+ }
+
+ /**
+ * 给 paramsMap 追加 timestamp、nonce、sign 三个参数
+ * @param paramsMap 参数列表
+ * @return 加工后的参数列表
+ */
+ public static Map addSignParams(Map paramsMap) {
+ return SaManager.getSaSignTemplate().addSignParams(paramsMap);
+ }
+
+ /**
+ * 给 paramsMap 追加 timestamp、nonce、sign 三个参数,并转换为参数字符串,形如:
+ * data=xxx8nonce=xxx8timestamp=xxx8sign=xxx
+ * @param paramsMap 参数列表
+ * @return 加工后的参数列表 转化为的参数字符串
+ */
+ public static String addSignParamsAndJoin(Map paramsMap) {
+ return SaManager.getSaSignTemplate().addSignParamsAndJoin(paramsMap);
+ }
+
+
+ // ----------- 校验签名
+
+ /**
+ * 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
+ * @param timestamp 待校验的时间戳
+ * @return 是否在允许的范围内
+ */
+ public static boolean isValidTimestamp(long timestamp) {
+ return SaManager.getSaSignTemplate().isValidTimestamp(timestamp);
+ }
+
+ /**
+ * 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
+ * @param timestamp 待校验的时间戳
+ */
+ public static void checkTimestamp(long timestamp) {
+ SaManager.getSaSignTemplate().checkTimestamp(timestamp);
+ }
+
+ /**
+ * 判断:随机字符串 nonce 是否有效。
+ * 注意:同一 nonce 可以被多次判断有效,不会被缓存
+ * @param nonce 待判断的随机字符串
+ * @return 是否有效
+ */
+ public static boolean isValidNonce(String nonce) {
+ return SaManager.getSaSignTemplate().isValidNonce(nonce);
+ }
+
+ /**
+ * 校验:随机字符串 nonce 是否有效,如果无效则抛出异常。
+ * 注意:同一 nonce 只可以被校验通过一次,校验后将保存在缓存中,再次校验将无法通过
+ * @param nonce 待校验的随机字符串
+ */
+ public static void checkNonce(String nonce) {
+ SaManager.getSaSignTemplate().checkNonce(nonce);
+ }
+
+ /**
+ * 判断:给定的参数 + 秘钥 生成的签名是否为有效签名
+ * @param paramsMap 参数列表
+ * @param sign 待验证的签名
+ * @return 签名是否有效
+ */
+ public static boolean isValidSign(Map paramsMap, String sign) {
+ return SaManager.getSaSignTemplate().isValidSign(paramsMap, sign);
+ }
+
+ /**
+ * 校验:给定的参数 + 秘钥 生成的签名是否为有效签名,如果签名无效则抛出异常
+ * @param paramsMap 参数列表
+ * @param sign 待验证的签名
+ */
+ public static void checkSign(Map paramsMap, String sign) {
+ SaManager.getSaSignTemplate().checkSign(paramsMap, sign);
+ }
+
+ /**
+ * 判断:参数列表中的 nonce、timestamp、sign 是否均为合法的
+ * @param paramMap 待校验的请求参数集合
+ * @return 是否合法
+ */
+ public static boolean isValidParamMap(Map paramMap) {
+ return SaManager.getSaSignTemplate().isValidParamMap(paramMap);
+ }
+
+ /**
+ * 校验:参数列表中的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
+ * @param paramMap 待校验的请求参数集合
+ */
+ public static void checkParamMap(Map paramMap) {
+ SaManager.getSaSignTemplate().checkParamMap(paramMap);
+ }
+
+ /**
+ * 判断:一个请求中的 nonce、timestamp、sign 是否均为合法的
+ * @param request 待校验的请求对象
+ * @return 是否合法
+ */
+ public static boolean isValidRequest(SaRequest request) {
+ return SaManager.getSaSignTemplate().isValidRequest(request);
+ }
+
+ /**
+ * 校验:一个请求的 nonce、timestamp、sign 是否均为合法的,如果不合法,则抛出对应的异常
+ * @param request 待校验的请求对象
+ */
+ public static void checkRequest(SaRequest request) {
+ SaManager.getSaSignTemplate().checkRequest(request);
+ }
+
+}
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 8c72a99f..d399e905 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
@@ -2,8 +2,8 @@ package com.pj.sso;
import cn.dev33.satoken.config.SaSsoConfig;
import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.sign.SaSignUtil;
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;
@@ -66,13 +66,13 @@ public class SsoServerController {
// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口)
@RequestMapping("/sso/getData")
- public Object userinfo(String apiType, String loginId) {
+ public Object getData(String apiType, String loginId) {
System.out.println("---------------- 获取数据 ----------------");
System.out.println("apiType=" + apiType);
System.out.println("loginId=" + loginId);
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
- SaSsoUtil.checkSign(SaHolder.getRequest());
+ SaSignUtil.checkRequest(SaHolder.getRequest());
// 自定义返回结果(模拟)
return SaResult.ok()
diff --git a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/resources/application.yml
index be264665..c7937759 100644
--- a/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/resources/application.yml
+++ b/sa-token-demo/sa-token-demo-sso/sa-token-demo-sso-server/src/main/resources/application.yml
@@ -15,14 +15,14 @@ sa-token:
ticket-timeout: 300
# 所有允许的授权回调地址
allow-url: "*"
- # 是否打开单点注销功能
- is-slo: true
-
- # ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
+
+ # ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
# 是否打开模式三
- isHttp: true
- # 接口调用秘钥(用于SSO模式三的单点注销功能)
- secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+ is-http: true
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
spring:
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 cf1d77a0..adbcbeef 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,21 +1,17 @@
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;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.dtflys.forest.Forest;
-
import cn.dev33.satoken.config.SaSsoConfig;
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.ExceptionHandler;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -65,7 +61,7 @@ public class SsoClientController {
map.put("loginId", StpUtil.getLoginId());
// 发起请求
- Object resData = SaSsoUtil.getData("/sso/getData", map);
+ Object resData = SaSsoUtil.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 67632540..a61bc655 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
@@ -8,18 +8,17 @@ sa-token:
sso:
# SSO-Server端 统一认证地址
auth-url: http://sa-sso-server.com:9000/sso/auth
- # 使用Http请求校验ticket
+ # 使用 Http 请求校验ticket (模式三)
is-http: true
# SSO-Server端 ticket校验地址
check-ticket-url: http://sa-sso-server.com:9000/sso/checkTicket
- # 打开单点注销功能
- is-slo: true
# 单点注销地址
slo-url: http://sa-sso-server.com:9000/sso/signout
- # 接口调用秘钥
- secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# 查询数据地址
get-data-url: http://sa-sso-server.com:9000/sso/getData
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
spring:
# 配置 Redis 连接 (此处与SSO-Server端连接不同的Redis)
diff --git a/sa-token-doc/sso/sso-questions.md b/sa-token-doc/sso/sso-questions.md
index 1d0b8843..2be82544 100644
--- a/sa-token-doc/sso/sso-questions.md
+++ b/sa-token-doc/sso/sso-questions.md
@@ -184,6 +184,13 @@ public class SsoUserServerController {
public StpLogic getStpLogic() {
return StpUserUtil.stpLogic;
}
+ // 使用自定义的签名秘钥
+ SaSignConfig signConfig = new SaSignConfig().setSecretKey("xxxx-新的秘钥-xxxx");
+ SaSignTemplate userSignTemplate = new SaSignTemplate().setSignConfig(signConfig);
+ @Override
+ public SaSignTemplate getSignTemplate() {
+ return userSignTemplate;
+ }
};
// 让这个SSO请求处理器,使用的路由前缀是 /sso-user,而不是原先的 /sso
ssoUserTemplate.apiName.replacePrefix("/sso-user");
diff --git a/sa-token-doc/sso/sso-server.md b/sa-token-doc/sso/sso-server.md
index 6b1288d1..06fd6a87 100644
--- a/sa-token-doc/sso/sso-server.md
+++ b/sa-token-doc/sso/sso-server.md
@@ -178,14 +178,13 @@ sa-token:
ticket-timeout: 300
# 所有允许的授权回调地址
allow-url: "*"
- # 是否打开单点注销功能
- is-slo: true
- # ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
+ # ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
# 是否打开模式三
- isHttp: true
- # 接口调用秘钥(用于SSO模式三的单点注销功能)
- secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+ is-http: true
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
spring:
@@ -219,14 +218,12 @@ server.port=9000
sa-token.sso.ticket-timeout=300
# 所有允许的授权回调地址
sa-token.sso.allow-url=*
-# 是否打开单点注销功能
-sa-token.sso.is-slo=true
-# ------- SSO-模式三相关配置 (下面的配置在SSO模式三并且 is-slo=true 时打开)
+# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
# 是否打开模式三
-sa-token.sso.isHttp=true
-# 接口调用秘钥(用于SSO模式三的单点注销功能)
-sa-token.sso.secretkey=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+sa-token.sso.is-http=true
+# API 接口调用秘钥
+sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
diff --git a/sa-token-doc/sso/sso-type2.md b/sa-token-doc/sso/sso-type2.md
index a38f3153..901cc9e1 100644
--- a/sa-token-doc/sso/sso-type2.md
+++ b/sa-token-doc/sso/sso-type2.md
@@ -173,8 +173,6 @@ sa-token:
sso:
# SSO-Server端 统一认证地址
auth-url: http://sa-sso-server.com:9000/sso/auth
- # 是否打开单点注销接口
- is-slo: true
# 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
alone-redis:
@@ -197,8 +195,6 @@ server.port=9001
######### Sa-Token 配置 #########
# SSO-Server端 统一认证地址
sa-token.sso.auth-url=http://sa-sso-server.com:9000/sso/auth
-# 是否打开单点注销接口
-sa-token.sso.is-slo=true
# 配置 Sa-Token 单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
# Redis数据库索引
diff --git a/sa-token-doc/sso/sso-type3.md b/sa-token-doc/sso/sso-type3.md
index ea504b69..194d6a4d 100644
--- a/sa-token-doc/sso/sso-type3.md
+++ b/sa-token-doc/sso/sso-type3.md
@@ -115,13 +115,13 @@ forest.log-enabled: false
``` java
// 示例:获取数据接口(用于在模式三下,为 client 端开放拉取数据的接口)
@RequestMapping("/sso/getData")
-public Object userinfo(String apiType, String loginId) {
+public Object getData(String apiType, String loginId) {
System.out.println("---------------- 获取数据 ----------------");
System.out.println("apiType=" + apiType);
System.out.println("loginId=" + loginId);
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
- SaSsoUtil.checkSign(SaHolder.getRequest());
+ SaSignUtil.checkRequest(SaHolder.getRequest());
// 自定义返回结果(模拟)
return SaResult.ok()
@@ -232,7 +232,7 @@ public Object getFansList(Long loginId) {
System.out.println("---------------- 获取 loginId=" + loginId + " 的粉丝列表 ----------------");
// 校验签名:只有拥有正确秘钥发起的请求才能通过校验
- SaSsoUtil.checkSign(SaHolder.getRequest());
+ SaSignUtil.checkRequest(SaHolder.getRequest());
// 查询数据 (此处仅做模拟)
List list = Arrays.asList(10041, 10042, 10043, 10044);
@@ -284,12 +284,11 @@ sa-token:
``` yaml
sa-token:
sso:
- # 打开单点注销功能
- is-slo: true
# 单点注销地址
slo-url: http://sa-sso-server.com:9000/sso/signout
- # 接口调用秘钥
- secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+ sign:
+ # API 接口调用秘钥
+ secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
```
``` properties
@@ -298,7 +297,7 @@ sa-token.sso.is-slo=true
# 单点注销地址
sa-token.sso.slo-url=http://sa-sso-server.com:9000/sso/signout
# 接口调用秘钥
-sa-token.sso.secretkey=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
+sa-token.sign.secret-key=kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
```
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 40e536d7..8909fcd8 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
@@ -43,11 +43,6 @@ public class SaSsoConfig implements Serializable {
*/
public Boolean isHttp = false;
- /**
- * 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
- */
- public String secretkey;
-
// ----------------- Client端相关配置
@@ -106,17 +101,6 @@ public class SaSsoConfig implements Serializable {
*/
public String serverUrl;
- // ----------------- 其它
-
-
-
- /**
- * 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距
- */
- public long timestampDisparity = 1000 * 60 * 10;
-
-
-
/**
* @return Ticket有效期 (单位: 秒)
@@ -182,22 +166,6 @@ public class SaSsoConfig implements Serializable {
return this;
}
- /**
- * @return 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
- */
- public String getSecretkey() {
- return secretkey;
- }
-
- /**
- * @param secretkey 接口调用秘钥 (用于SSO模式三单点注销的接口通信身份校验)
- * @return 对象自身
- */
- public SaSsoConfig setSecretkey(String secretkey) {
- this.secretkey = secretkey;
- return this;
- }
-
/**
* @return 当前 Client 名称标识,用于和 ticket 码的互相锁定
*/
@@ -325,30 +293,13 @@ public class SaSsoConfig implements Serializable {
return this;
}
- /**
- * @return 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距
- */
- public long getTimestampDisparity() {
- return timestampDisparity;
- }
-
- /**
- * @param timestampDisparity 接口调用时的时间戳允许的差距(单位:ms),-1代表不校验差距
- * @return 对象自身
- */
- public SaSsoConfig setTimestampDisparity(long timestampDisparity) {
- this.timestampDisparity = timestampDisparity;
- return this;
- }
-
@Override
public String toString() {
return "SaSsoConfig ["
+ "ticketTimeout=" + ticketTimeout
+ ", allowUrl=" + allowUrl
+ ", isSlo=" + isSlo
- + ", isHttp=" + isHttp
- + ", secretkey=" + secretkey
+ + ", isHttp=" + isHttp
+ ", client=" + client
+ ", authUrl=" + authUrl
+ ", checkTicketUrl=" + checkTicketUrl
@@ -356,8 +307,7 @@ public class SaSsoConfig implements Serializable {
+ ", userinfoUrl=" + userinfoUrl
+ ", sloUrl=" + sloUrl
+ ", ssoLogoutCall=" + ssoLogoutCall
- + ", serverUrl=" + serverUrl
- + ", timestampDisparity=" + timestampDisparity
+ + ", serverUrl=" + serverUrl
+ "]";
}
diff --git a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoProcessor.java b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoProcessor.java
index bcb1d227..b75702bd 100644
--- a/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoProcessor.java
+++ b/sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/SaSsoProcessor.java
@@ -193,7 +193,7 @@ public class SaSsoProcessor {
String loginId = req.getParam(paramName.loginId);
// step.1 校验签名
- ssoTemplate.checkSign(req);
+ ssoTemplate.getSignTemplate().checkRequest(req);
// step.2 单点注销
ssoTemplate.ssoLogout(loginId);
@@ -374,7 +374,7 @@ public class SaSsoProcessor {
String loginId = req.getParamNotNull(paramName.loginId);
// 注销当前应用端会话
- ssoTemplate.checkSign(req);
+ ssoTemplate.getSignTemplate().checkRequest(req);
stpLogic.logout(loginId);
// 响应
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 128427f6..4386090a 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
@@ -2,8 +2,8 @@ package cn.dev33.satoken.sso;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaSsoConfig;
-import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.sign.SaSignTemplate;
import cn.dev33.satoken.sso.error.SaSsoErrorCode;
import cn.dev33.satoken.sso.exception.SaSsoException;
import cn.dev33.satoken.sso.name.ApiName;
@@ -68,8 +68,16 @@ public class SaSsoTemplate {
public SaSsoConfig getSsoConfig() {
return SaSsoManager.getConfig();
}
-
-
+
+ /**
+ * 获取底层使用的 API 签名对象
+ * @return /
+ */
+ public SaSignTemplate getSignTemplate() {
+ return SaManager.getSaSignTemplate();
+ }
+
+
// ---------------------- Ticket 操作 ----------------------
/**
@@ -300,7 +308,7 @@ public class SaSsoTemplate {
SaSsoConfig cfg = SaSsoManager.getConfig();
Set urlSet = session.get(SaSsoConsts.SLO_CALLBACK_SET_KEY, HashSet::new);
for (String url : urlSet) {
- url = addSignParams(url, loginId);
+ url = joinLoginIdAndSign(url, loginId);
cfg.getSendHttp().apply(url);
}
@@ -452,7 +460,7 @@ public class SaSsoTemplate {
*/
public String buildSloUrl(Object loginId) {
String url = SaSsoManager.getConfig().splicingSloUrl();
- return addSignParams(url, loginId);
+ return joinLoginIdAndSign(url, loginId);
}
/**
@@ -480,32 +488,11 @@ public class SaSsoTemplate {
}
// 添加签名等参数,并序列化
- return addSignParams(url, paramMap);
- }
-
-
- // ------------------- 返回相应key -------------------
-
- /**
- * 拼接key:Ticket 查 账号Id
- * @param ticket ticket值
- * @return key
- */
- public String splicingTicketSaveKey(String ticket) {
- return SaManager.getConfig().getTokenName() + ":ticket:" + ticket;
- }
-
- /**
- * 拼接key:账号Id 反查 Ticket
- * @param id 账号id
- * @return key
- */
- public String splicingTicketIndexKey(Object id) {
- return SaManager.getConfig().getTokenName() + ":id-ticket:" + id;
+ return joinParamMapAndSign(url, paramMap);
}
- // ------------------- 请求相关 -------------------
+ // ------------------- 发起请求 -------------------
/**
* 发出请求,并返回 SaResult 结果
@@ -518,33 +505,20 @@ public class SaSsoTemplate {
return new SaResult(map);
}
- /**
- * 获取:接口调用秘钥
- * @return see note
- */
- public String getSecretkey() {
- // 默认从配置文件中返回
- String secretkey = SaSsoManager.getConfig().getSecretkey();
- if(SaFoxUtil.isEmpty(secretkey)) {
- throw new SaSsoException("请配置 secretkey 参数").setCode(SaSsoErrorCode.CODE_30009);
- }
- return secretkey;
- }
-
/**
* 给 paramMap 追加 sign 等参数,并序列化为kv字符串,拼接到url后面
* @param url 请求地址
* @param paramMap 请求原始参数列表
* @return 加工后的url
*/
- public String addSignParams(String url, Map paramMap) {
- // 追加:时间戳、随机字符串、参数签名
- SaManager.getSaSignTemplate().addSignParams(paramMap, getSecretkey());
+ public String joinParamMapAndSign(String url, Map paramMap) {
+ // 在参数列表中追加:时间戳、随机字符串、参数签名
+ SaManager.getSaSignTemplate().addSignParams(paramMap);
- // 序列化为kv字符串
+ // 将参数列表序列化为kv字符串
String signParams = SaManager.getSaSignTemplate().joinParams(paramMap);
- // 拼接到一起
+ // 将kv字符串拼接到url后面
return SaFoxUtil.joinParam(url, signParams);
}
@@ -554,51 +528,36 @@ public class SaSsoTemplate {
* @param loginId 账号id
* @return 加工后的url
*/
- public String addSignParams(String url, Object loginId) {
+ public String joinLoginIdAndSign(String url, Object loginId) {
Map paramMap = new LinkedHashMap<>();
paramMap.put(paramName.loginId, loginId);
- return addSignParams(url, paramMap);
+ return joinParamMapAndSign(url, paramMap);
+ }
+
+
+ // ------------------- 返回相应key -------------------
+
+ /**
+ * 拼接key:Ticket 查 账号Id
+ * @param ticket ticket值
+ * @return key
+ */
+ public String splicingTicketSaveKey(String ticket) {
+ return SaManager.getConfig().getTokenName() + ":ticket:" + ticket;
}
/**
- * 校验签名
- * @param req request
+ * 拼接key:账号Id 反查 Ticket
+ * @param id 账号id
+ * @return key
*/
- 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);
+ public String splicingTicketIndexKey(Object id) {
+ return SaManager.getConfig().getTokenName() + ":id-ticket:" + id;
}
// -------- 以下方法已废弃,仅为兼容旧版本而保留 --------
- /**
- * 根据参数计算签名
- * @param loginId 账号id
- * @param timestamp 当前时间戳,13位
- * @param nonce 随机字符串
- * @param secretkey 账号id
- * @return 签名
- */
- @Deprecated
- public String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
- Map map = new TreeMap<>();
- map.put(paramName.loginId, loginId);
- map.put(paramName.timestamp, timestamp);
- map.put(paramName.nonce, nonce);
- return SaManager.getSaSignTemplate().createSign(map, secretkey);
- }
-
/**
* 构建URL:Server端 账号资料查询地址
* @param loginId 账号id
@@ -607,7 +566,7 @@ public class SaSsoTemplate {
@Deprecated
public String buildUserinfoUrl(Object loginId) {
String userinfoUrl = SaSsoManager.getConfig().splicingUserinfoUrl();
- return addSignParams(userinfoUrl, loginId);
+ return joinLoginIdAndSign(userinfoUrl, loginId);
}
/**
@@ -618,7 +577,7 @@ public class SaSsoTemplate {
@Deprecated
public Object getUserinfo(Object loginId) {
String url = buildUserinfoUrl(loginId);
- return SaSsoManager.getConfig().getSendHttp().apply(url);
+ return request(url);
}
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 4388c043..a4fc2880 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
@@ -1,6 +1,5 @@
package cn.dev33.satoken.sso;
-import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.util.SaResult;
import java.util.Map;
@@ -202,7 +201,7 @@ public class SaSsoUtil {
}
- // ------------------- 请求相关 -------------------
+ // ------------------- 发起请求 -------------------
/**
* 发出请求,并返回 SaResult 结果
@@ -219,8 +218,8 @@ public class SaSsoUtil {
* @param paramMap 请求原始参数列表
* @return 加工后的url
*/
- public static String addSignParams(String url, Map paramMap) {
- return ssoTemplate.addSignParams(url, paramMap);
+ public static String joinParamMapAndSign(String url, Map paramMap) {
+ return ssoTemplate.joinLoginIdAndSign(url, paramMap);
}
/**
@@ -229,32 +228,21 @@ public class SaSsoUtil {
* @param loginId 账号id
* @return 加工后的url
*/
- public static String addSignParams(String url, Object loginId) {
- return ssoTemplate.addSignParams(url, loginId);
- }
-
- /**
- * 校验签名
- * @param req request
- */
- public static void checkSign(SaRequest req) {
- ssoTemplate.checkSign(req);
+ public static String joinLoginIdAndSign(String url, Object loginId) {
+ return ssoTemplate.joinLoginIdAndSign(url, loginId);
}
// -------- 以下方法已废弃,仅为兼容旧版本而保留 --------
/**
- * 根据参数计算签名
+ * 构建URL:Server端 账号资料查询地址
* @param loginId 账号id
- * @param timestamp 当前时间戳,13位
- * @param nonce 随机字符串
- * @param secretkey 账号id
- * @return 签名
+ * @return Server端 账号资料查询地址
*/
@Deprecated
- public static String getSign(Object loginId, String timestamp, String nonce, String secretkey) {
- return ssoTemplate.getSign(loginId, timestamp, nonce, secretkey);
+ public static String buildUserinfoUrl(Object loginId) {
+ return ssoTemplate.buildUserinfoUrl(loginId);
}
/**
@@ -267,14 +255,4 @@ public class SaSsoUtil {
return ssoTemplate.getUserinfo(loginId);
}
- /**
- * 构建URL:Server端 账号资料查询地址
- * @param loginId 账号id
- * @return Server端 账号资料查询地址
- */
- @Deprecated
- public static String buildUserinfoUrl(Object loginId) {
- return ssoTemplate.buildUserinfoUrl(loginId);
- }
-
}