checkTokenFunction
+ );
+
+}
\ No newline at end of file
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java
index 60f6d355..b31c8fce 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java
@@ -421,8 +421,17 @@ public class StpLogic {
}
}
- // 如果代码走到此处,说明未能成功复用旧Token,需要新建Token
- return createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData());
+ // 如果代码走到此处,说明未能成功复用旧Token,需要新建Token
+ return SaStrategy.me.generateUniqueToken.execute(
+ "token",
+ getConfigOfMaxTryTimes(),
+ () -> {
+ return createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData());
+ },
+ tokenValue -> {
+ return getLoginIdNotHandle(tokenValue) == null;
+ }
+ );
}
// --- 注销
@@ -1036,7 +1045,17 @@ public class StpLogic {
*/
if(isCreate) {
// 随机创建一个 Token
- tokenValue = createTokenValue(null, null, getConfig().getTimeout(), null);
+ tokenValue = SaStrategy.me.generateUniqueToken.execute(
+ "token",
+ getConfigOfMaxTryTimes(),
+ () -> {
+ return createTokenValue(null, null, getConfig().getTimeout(), null);
+ },
+ token -> {
+ return getTokenSessionByToken(token, false) == null;
+ }
+ );
+
// 写入 [最后操作时间]
setLastActivityToNow(tokenValue);
// 在当前上下文写入此 TokenValue
@@ -2305,6 +2324,14 @@ public class StpLogic {
return (int) timeout;
}
+ /**
+ * 返回全局配置的 maxTryTimes 值,在每次创建 token 时,对其唯一性测试的最高次数(-1=不测试)
+ * @return /
+ */
+ public int getConfigOfMaxTryTimes() {
+ return getConfig().getMaxTryTimes();
+ }
+
/**
* 返回持久化对象
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java
index 56186e97..4b0095dd 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java
@@ -1,5 +1,14 @@
package cn.dev33.satoken.strategy;
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.annotation.*;
+import cn.dev33.satoken.basic.SaBasicUtil;
+import cn.dev33.satoken.exception.SaTokenException;
+import cn.dev33.satoken.fun.SaGenerateUniqueTokenFunction;
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.util.SaFoxUtil;
+import cn.dev33.satoken.util.SaTokenConsts;
+
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
@@ -8,18 +17,7 @@ import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
-
-import cn.dev33.satoken.SaManager;
-import cn.dev33.satoken.annotation.SaCheckBasic;
-import cn.dev33.satoken.annotation.SaCheckDisable;
-import cn.dev33.satoken.annotation.SaCheckLogin;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import cn.dev33.satoken.annotation.SaCheckRole;
-import cn.dev33.satoken.annotation.SaCheckSafe;
-import cn.dev33.satoken.basic.SaBasicUtil;
-import cn.dev33.satoken.session.SaSession;
-import cn.dev33.satoken.util.SaFoxUtil;
-import cn.dev33.satoken.util.SaTokenConsts;
+import java.util.function.Supplier;
/**
* Sa-Token 策略对象
@@ -47,9 +45,7 @@ public final class SaStrategy {
*/
public static final SaStrategy me = new SaStrategy();
- //
- // 所有策略
- //
+ // ----------------------- 所有策略
/**
* 创建 Token 的策略
@@ -194,11 +190,38 @@ public final class SaStrategy {
me.getAnnotation.apply(method.getDeclaringClass(), annotationClass) != null;
};
+ /**
+ * 生成唯一式 token 的算法
+ * 参数 [元素名称, 最大尝试次数, 创建 token 函数, 检查 token 函数]
+ */
+ public SaGenerateUniqueTokenFunction generateUniqueToken = (elementName, maxTryTimes, createTokenFunction, checkTokenFunction) -> {
- //
- // 重写策略 set连缀风格
- //
-
+ // 为方便叙述,以下代码注释均假设在处理生成 token 的场景,但实际上本方法也可能被用于生成 code、ticket 等
+
+ // 循环生成
+ for (int i = 1; ; i++) {
+ // 生成 token
+ String token = createTokenFunction.get();
+
+ // 如果 maxTryTimes == -1,表示不做唯一性验证,直接返回
+ if (maxTryTimes == -1) {
+ return token;
+ }
+
+ // 如果 token 在DB库查询不到数据,说明是个可用的全新 token,直接返回
+ if (checkTokenFunction.apply(token)) {
+ return token;
+ }
+
+ // 如果已经循环了 maxTryTimes 次,仍然没有创建出可用的 token,那么抛出异常
+ if (i >= maxTryTimes) {
+ throw new SaTokenException(elementName + " 生成失败,已尝试" + i + "次,生成算法过于简单或资源池已耗尽");
+ }
+ }
+ };
+
+
+ // ----------------------- 重写策略 set连缀风格
/**
* 重写创建 Token 的策略
@@ -276,5 +299,17 @@ public final class SaStrategy {
this.isAnnotationPresent = isAnnotationPresent;
return this;
}
-
+
+ /**
+ * 生成唯一式 token 的算法
+ *
参数 [元素名称, 最大尝试次数, 创建 token 函数, 检查 token 函数]
+ *
+ * @param generateUniqueToken /
+ * @return 对象自身
+ */
+ public SaStrategy setGenerateUniqueToken(SaGenerateUniqueTokenFunction generateUniqueToken) {
+ this.generateUniqueToken = generateUniqueToken;
+ return this;
+ }
+
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java
index 40edc4d0..4dc0509f 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java
@@ -1,5 +1,8 @@
package cn.dev33.satoken.util;
+import cn.dev33.satoken.error.SaErrorCode;
+import cn.dev33.satoken.exception.SaTokenException;
+
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -8,19 +11,10 @@ import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
-import cn.dev33.satoken.error.SaErrorCode;
-import cn.dev33.satoken.exception.SaTokenException;
-
/**
* Sa-Token 内部工具类
*
diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/SaTokenDemoApplication.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/SaTokenDemoApplication.java
index 4f5e4467..7c01ff54 100644
--- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/SaTokenDemoApplication.java
+++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/SaTokenDemoApplication.java
@@ -1,10 +1,9 @@
package com.pj;
+import cn.dev33.satoken.SaManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import cn.dev33.satoken.SaManager;
-
/**
* Sa-Token整合SpringBoot 示例,整合redis
* @author kong
diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java
index d0aa2580..308bcaa8 100644
--- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java
+++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/test/TestController.java
@@ -17,7 +17,7 @@ public class TestController {
// 测试 浏览器访问: http://localhost:8081/test/test
@RequestMapping("test")
public SaResult test() {
- System.out.println("------------进来了");
+ System.out.println("------------进来了");
return SaResult.ok();
}
diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml
index 3a41ae12..fdb03d91 100644
--- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml
+++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml
@@ -18,7 +18,7 @@ sa-token:
token-style: uuid
# 是否输出操作日志
is-log: true
-
+
spring:
# redis配置
redis:
From 453030058f476a7acabd051ee8142c32f920b5d7 Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Sun, 30 Apr 2023 23:02:04 +0800
Subject: [PATCH 06/12] =?UTF-8?q?=E4=B8=BA=20jwt-mixin=20=E6=A8=A1?=
=?UTF-8?q?=E5=BC=8F=E9=80=82=E9=85=8D=20max-try-times=20=E5=B1=9E?=
=?UTF-8?q?=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/cn/dev33/satoken/stp/StpLogic.java | 4 ++--
sa-token-demo/sa-token-demo-jwt/pom.xml | 4 ++--
sa-token-doc/plugin/jwt-extend.md | 6 ++++++
sa-token-doc/use/config.md | 3 ++-
.../cn/dev33/satoken/jwt/StpLogicJwtForMixin.java | 13 +++++++++++--
5 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java
index b31c8fce..09ea2826 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java
@@ -351,7 +351,7 @@ public class StpLogic {
* @return 返回会话令牌
*/
public String createLoginSession(Object id, SaLoginModel loginModel) {
-
+
// ------ 前置检查
SaTokenException.throwByNull(id, "账号id不能为空", SaErrorCode.CODE_11002);
@@ -395,7 +395,7 @@ public class StpLogic {
* @return 返回 Token
*/
protected String distUsableToken(Object id, SaLoginModel loginModel) {
-
+
// 获取全局配置
Boolean isConcurrent = getConfig().getIsConcurrent();
diff --git a/sa-token-demo/sa-token-demo-jwt/pom.xml b/sa-token-demo/sa-token-demo-jwt/pom.xml
index 8f184e81..9e200919 100644
--- a/sa-token-demo/sa-token-demo-jwt/pom.xml
+++ b/sa-token-demo/sa-token-demo-jwt/pom.xml
@@ -42,7 +42,7 @@
-
+
diff --git a/sa-token-doc/plugin/jwt-extend.md b/sa-token-doc/plugin/jwt-extend.md
index d5b17e50..7aed51f9 100644
--- a/sa-token-doc/plugin/jwt-extend.md
+++ b/sa-token-doc/plugin/jwt-extend.md
@@ -234,6 +234,12 @@ public void setSaJwtTemplate() {
技术上来讲无法将其踢下线,所以此时顶人下线和踢人下线等 API 都属于不可用状态,所以此时 `is-concurrent` 配置项必须配置为 `true`。
+##### 3、使用 jwt-mixin 模式后,max-try-times 恒等于 -1。
+
+为防止框架错误判断 token 唯一性,当使用 jwt-mixin 模式后,`max-try-times` 恒等于 -1。
+
+
+
diff --git a/sa-token-doc/use/config.md b/sa-token-doc/use/config.md
index aa5bd486..7544bd3e 100644
--- a/sa-token-doc/use/config.md
+++ b/sa-token-doc/use/config.md
@@ -110,7 +110,7 @@ public class SaTokenConfigure {
---
### 所有可配置项
-你不必立刻掌握整个表格,只需要在用到某个功能时再详细查阅它即可
+**你不必立刻掌握整个表格,只需要在用到某个功能时再详细查阅它即可**
| 参数名称 | 类型 | 默认值 | 说明 |
| :-------- | :-------- | :-------- | :-------- |
@@ -120,6 +120,7 @@ public class SaTokenConfigure {
| isConcurrent | Boolean | true | 是否允许同一账号并发登录 (为 true 时允许一起登录,为 false 时新登录挤掉旧登录) |
| isShare | Boolean | true | 在多人登录同一账号时,是否共用一个token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) |
| maxLoginCount | int | 12 | 同一账号最大登录数量,-1代表不限 (只有在 `isConcurrent=true`, `isShare=false` 时此配置才有效),[详解](/use/config?id=配置项详解:maxlogincount) |
+| maxTryTimes | int | 12 | 在每次创建 Token 时的最高循环次数,用于保证 Token 唯一性(-1=不循环重试,直接使用) |
| isReadBody | Boolean | true | 是否尝试从 请求体 里读取 Token |
| isReadHeader | Boolean | true | 是否尝试从 header 里读取 Token |
| isReadCookie | Boolean | true | 是否尝试从 cookie 里读取 Token,此值为 false 后,`StpUtil.login(id)` 登录时也不会再往前端注入Cookie |
diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java
index 21e7fe3f..5b2612bb 100644
--- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java
+++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java
@@ -212,12 +212,21 @@ public class StpLogicJwtForMixin extends StpLogic {
// ------------------- Bean对象代理 -------------------
/**
- * 返回全局配置对象的isShare属性
+ * 返回全局配置对象的 isShare 属性
* @return /
*/
@Override
public boolean getConfigOfIsShare() {
return false;
}
-
+
+ /**
+ * 返回全局配置对象的 maxTryTimes 属性
+ * @return /
+ */
+ @Override
+ public int getConfigOfMaxTryTimes() {
+ return -1;
+ }
+
}
From 3a84c3d51e8481f8486feb33e0967581068701ba Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Mon, 1 May 2023 02:56:42 +0800
Subject: [PATCH 07/12] =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=A2=9E=E5=8A=A0=20Co?=
=?UTF-8?q?okie=20=E9=85=8D=E7=BD=AE=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sa-token-doc/use/config.md | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/sa-token-doc/use/config.md b/sa-token-doc/use/config.md
index 7544bd3e..53cadbf7 100644
--- a/sa-token-doc/use/config.md
+++ b/sa-token-doc/use/config.md
@@ -149,6 +149,31 @@ Cookie相关配置:
| httpOnly | Boolean | false | 是否禁止 js 操作 Cookie |
| sameSite | String | Lax | 第三方限制级别(Strict=完全禁止,Lax=部分允许,None=不限制) |
+Cookie 配置示例:
+
+
+
+``` yaml
+# Sa-Token 配置
+sa-token:
+ # Cookie 相关配置
+ cookie:
+ domain: stp.com
+ path: /
+ secure: false
+ httpOnly: true
+ sameSite: Lax
+```
+
+``` properties
+# Cookie 相关配置
+sa-token.cookie.domain=stp.com
+sa-token.cookie.path=/
+sa-token.cookie.secure=false
+sa-token.cookie.httpOnly=true
+sa-token.cookie.sameSite=Lax
+```
+
### 单点登录相关配置
From 68e99f232e7497125258af61aac670bbac7fcd9a Mon Sep 17 00:00:00 2001
From: noear
Date: Mon, 1 May 2023 09:37:50 +0800
Subject: [PATCH 08/12] =?UTF-8?q?=E5=B0=86=E5=85=A8=E5=B1=80=E8=BF=87?=
=?UTF-8?q?=E6=BB=A4=E5=99=A8=E7=9A=84=20BeforeAuth=20=E8=AE=A4=E8=AF=81?=
=?UTF-8?q?=E8=AE=BE=E4=B8=BA=E4=B8=8D=E5=8F=97=20includeList=20=E4=B8=8E?=
=?UTF-8?q?=20excludeList=20=E7=9A=84=E9=99=90=E5=88=B6=EF=BC=8C=E6=89=80?=
=?UTF-8?q?=E6=9C=89=E8=AF=B7=E6=B1=82=E9=83=BD=E4=BC=9A=E8=BF=9B=E5=85=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../satoken/solon/integration/SaTokenFilter.java | 3 ++-
.../solon/integration/SaTokenInterceptor.java | 12 ++++++------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java
index 7179865d..5331ab03 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java
@@ -123,11 +123,12 @@ public class SaTokenFilter implements SaFilter, Filter { //之所以改名,为
Handler mainHandler = Solon.app().router().matchMain(ctx);
Action action = (mainHandler instanceof Action ? (Action) mainHandler : null);
- //先路径过滤下(包括了静态文件)
//1.执行前置处理(主要是一些跨域之类的)
if(beforeAuth != null) {
beforeAuth.run(mainHandler);
}
+
+ //先路径过滤下(包括了静态文件)
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
//2.执行注解处理
if(authAnno(action)) {
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java
index 0afb5a82..a9554c76 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java
@@ -172,19 +172,19 @@ public class SaTokenInterceptor implements RouterInterceptor {
try {
Action action = (mainHandler instanceof Action ? (Action) mainHandler : null);
- //先路径过滤下(包括了静态文件)
+ //1.执行前置处理(主要是一些跨域之类的)
+ if(beforeAuth != null) {
+ beforeAuth.run(mainHandler);
+ }
+
+ //先路径过滤下(不包括静态文件)
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
- //1.执行前置处理(主要是一些跨域之类的)
- if(beforeAuth != null) {
- beforeAuth.run(mainHandler);
- }
//2.执行注解处理
if(authAnno(action)) {
//3.执行规则处理(如果没有被 @SaIgnore 忽略)
auth.run(mainHandler);
}
});
-
} catch (StopMatchException e) {
} catch (SaTokenException e) {
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 09/12] =?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);
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 10/12] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9AAPI=20?=
=?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=AD=BE=E5=90=8D=E6=89=80=E6=9C=89=E6=96=B9?=
=?UTF-8?q?=E6=B3=95=E5=9D=87=E8=BF=81=E7=A7=BB=E8=87=B3=20core=20?=
=?UTF-8?q?=E6=A0=B8=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);
- }
-
}
From ca65c2d9fd31917683cfb8b33fc50eaf4d13f79f Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Wed, 3 May 2023 04:53:35 +0800
Subject: [PATCH 11/12] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
sa-token-doc/sso/sso-questions.md | 3 +++
sa-token-doc/use/config.md | 6 +++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/sa-token-doc/sso/sso-questions.md b/sa-token-doc/sso/sso-questions.md
index 2be82544..30bd127c 100644
--- a/sa-token-doc/sso/sso-questions.md
+++ b/sa-token-doc/sso/sso-questions.md
@@ -57,6 +57,9 @@ public class SaSsoServerApplication {
解决方案:在 sso-client 也新建上这个类,而且包名需要与 sso-server 端的一致(直接从 sso-server 把实体类复制过来就好了)
+### 模式三配置一堆 xxx-url ,有办法简化一下吗?
+可以使用 `sa-token.sso.server-url` 配置项来简化,参考:[配置项详解:serverurl](/use/config?id=配置项详解:serverurl)
+
### 问:SSO模式二或模式三,第一个 client 登录成功之后再访问其它两个 client 不会自动登录,需要点一下登录按钮才会登录上?
答:这是正常现象,系统 1 登录成功之后,系统 2 与系统 3 需要点击登录按钮,才会登录成功。
diff --git a/sa-token-doc/use/config.md b/sa-token-doc/use/config.md
index 53cadbf7..02308f84 100644
--- a/sa-token-doc/use/config.md
+++ b/sa-token-doc/use/config.md
@@ -345,7 +345,7 @@ sa-token.oauth2.is-client=true
#### 配置项详解:serverUrl
-配置含义:配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、userinfoUrl、sloUrl 属性前面,用以简化各种 url 配置。
+配置含义:配置 Server 端主机总地址,拼接在 authUrl、checkTicketUrl、getDataUrl、sloUrl 属性前面,用以简化各种 url 配置。
在开发 SSO 模块时,我们需要在 sso-client 配置认证中心的各种地址,特别是在模式三下,一般代码会变成这样:
@@ -358,8 +358,8 @@ sa-token:
check-ticket-url: http://sa-sso-server.com:9000/sso/checkTicket
# 单点注销地址
slo-url: http://sa-sso-server.com:9000/sso/signout
- # 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
```
一堆 xxx-url 配置比较繁琐,且含有大量重复字符,现在我们可以将其简化为:
From fc4d9a8f6202686a22e75af189da122585afec73 Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Wed, 3 May 2023 05:09:15 +0800
Subject: [PATCH 12/12] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/com/pj/current/GlobalException.java | 2 +-
.../src/main/resources/application.yml | 2 +-
sa-token-doc/more/common-questions.md | 6 ++++++
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java
index 7ee67369..1d6ebb1c 100644
--- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java
+++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/java/com/pj/current/GlobalException.java
@@ -26,7 +26,7 @@ public class GlobalException {
// 打印堆栈,以供调试
System.out.println("全局异常---------------");
- e.printStackTrace();
+ e.printStackTrace();
// 不同异常返回不同状态码
AjaxJson aj = null;
diff --git a/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml
index fdb03d91..55685ecb 100644
--- a/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml
+++ b/sa-token-demo/sa-token-demo-springboot-redis/src/main/resources/application.yml
@@ -19,7 +19,7 @@ sa-token:
# 是否输出操作日志
is-log: true
-spring:
+spring:
# redis配置
redis:
# Redis数据库索引(默认为0)
diff --git a/sa-token-doc/more/common-questions.md b/sa-token-doc/more/common-questions.md
index 368dc982..6eb729fb 100644
--- a/sa-token-doc/more/common-questions.md
+++ b/sa-token-doc/more/common-questions.md
@@ -428,6 +428,12 @@ Caused by: java.lang.ClassNotFoundException: cn.dev33.satoken.same.SaSameTemplat
- (2) 在自定义StpUtil类加上类似 @Component 的注解让容器启动时扫描到自动初始化
+### Q:使用拦截器鉴权,访问一个不存在的 path 时,springboot 会自动在控制台打印一下异常。
+可尝试添加以下配置解决:
+``` properties
+spring.resources.add-mappings=false
+spring.mvc.throw-exception-if-no-handler-found=true
+```