From 55f0c94aece2db85d62924eb77c8e138a64afe72 Mon Sep 17 00:00:00 2001
From: click33 <2393584716@qq.com>
Date: Sun, 6 Apr 2025 23:22:01 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=89=80?=
=?UTF-8?q?=E6=9C=89=20starter=20=E7=BB=84=E4=BB=B6=E7=9A=84=20SaTokenCont?=
=?UTF-8?q?ext=20=E4=B8=8A=E4=B8=8B=E6=96=87=E8=AF=BB=E5=86=99=E7=AD=96?=
=?UTF-8?q?=E7=95=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/cn/dev33/satoken/SaManager.java | 30 ++--
.../cn/dev33/satoken/context/SaHolder.java | 8 +-
.../dev33/satoken/context/SaTokenContext.java | 16 +-
.../context/SaTokenContextDefaultImpl.java | 5 -
.../context/SaTokenContextForThreadLocal.java | 5 -
.../cn/dev33/satoken/error/SaErrorCode.java | 5 +
.../satoken/fun/SaRetGenericFunction.java | 26 ++-
.../fun/strategy/SaRouteMatchFunction.java | 27 ++-
.../cn/dev33/satoken/router/SaRouter.java | 8 +-
.../cn/dev33/satoken/strategy/SaStrategy.java | 9 +
.../cn/dev33/satoken/util/SaTokenConsts.java | 12 +-
.../src/main/java/com/pj/SaTokenDemoApp.java | 1 +
.../main/java/com/pj/test/TestController.java | 5 +-
sa-token-demo/sa-token-demo-test/pom.xml | 6 +-
.../java/com/pj/test/Test2Controller.java | 12 +-
.../sa-token-demo-webflux-springboot3/pom.xml | 19 +--
.../java/com/pj/satoken/SaTokenConfigure.java | 8 +-
.../main/java/com/pj/test/DefineRoutes.java | 18 +-
.../java/com/pj/test/GlobalException.java | 45 +----
.../main/java/com/pj/test/TestController.java | 137 ++++++++++------
.../main/java/com/pj/test/UserService.java | 25 +++
.../src/main/java/com/pj/util/AjaxJson.java | 154 ------------------
sa-token-demo/sa-token-demo-webflux/pom.xml | 21 +--
.../com/pj/SaTokenWebfluxApplication.java | 3 +-
.../java/com/pj/satoken/SaTokenConfigure.java | 4 +-
.../main/java/com/pj/test/DefineRoutes.java | 18 +-
.../java/com/pj/test/GlobalException.java | 45 +----
.../main/java/com/pj/test/TestController.java | 127 ++++++++++-----
.../main/java/com/pj/test/UserService.java | 25 +++
.../src/main/java/com/pj/util/AjaxJson.java | 154 ------------------
sa-token-dependencies/pom.xml | 3 +-
.../dubbo/SaTokenSecondContextForDubbo.java | 9 +-
.../filter/SaTokenDubboConsumerFilter.java | 2 +-
.../dubbo3/SaTokenSecondContextForDubbo3.java | 6 -
.../filter/SaTokenDubbo3ConsumerFilter.java | 2 +-
.../grpc/SaTokenSecondContextForGrpc.java | 6 -
.../SaTokenGrpcClientInterceptor.java | 2 +-
.../servlet/model/SaRequestForServlet.java | 2 +-
.../util/SaJakartaServletOperateUtil.java | 48 ++++++
.../servlet/util/SaTokenContextUtil.java | 99 +++++++++++
.../satoken/jboot/SaTokenContextForJboot.java | 17 +-
.../jfinal/SaTokenContextForJfinal.java | 17 +-
.../satoken/jfinal/SaTokenPathFilter.java | 2 +-
.../pom.xml | 26 +--
.../reactor/context/SaReactorHolder.java | 79 ++++++---
.../reactor/context/SaReactorSyncHolder.java | 43 +++--
.../SaFirewallCheckFilterForReactor.java | 17 +-
.../reactor/filter/SaReactorFilter.java | 63 ++-----
.../SaTokenContextFilterForReactor.java | 59 +++++++
.../reactor/model/SaRequestForReactor.java | 2 +-
.../SaTokenContextForSpringReactor.java | 13 +-
.../spring/SaTokenContextRegister.java | 30 ++--
...SpringBootVersionCompatibilityChecker.java | 3 +-
.../reactor/util/SaReactorOperateUtil.java | 46 ++++++
.../pom.xml | 35 +---
.../reactor/context/SaReactorHolder.java | 87 +++++++---
.../reactor/context/SaReactorSyncHolder.java | 49 +++---
.../SaFirewallCheckFilterForReactor.java | 19 ++-
.../reactor/filter/SaReactorFilter.java | 67 ++------
.../SaTokenContextFilterForReactor.java | 44 +++++
.../reactor/model/SaRequestForReactor.java | 2 +-
.../SaTokenContextForSpringReactor.java | 17 +-
.../spring/SaTokenContextRegister.java | 19 ++-
.../reactor/util/SaReactorOperateUtil.java | 46 ++++++
.../servlet/model/SaRequestForServlet.java | 2 +-
.../servlet/util/SaServletOperateUtil.java | 48 ++++++
.../servlet/util/SaTokenContextUtil.java | 99 +++++++++++
.../dev33/satoken/solon/SaBeanRegister.java | 22 ++-
.../cn/dev33/satoken/solon/SaSolonPlugin.java | 3 -
.../SaFirewallCheckFilterForSolon.java | 12 +-
.../SaTokenContextFilterForSolon.java | 41 +++++
.../solon/integration/SaTokenFilter.java | 27 ++-
.../solon/integration/SaTokenInterceptor.java | 25 +--
.../solon/model/SaContextForSolon.java | 12 +-
.../solon/model/SaRequestForSolon.java | 6 +-
.../solon/model/SaResponseForSolon.java | 6 +-
.../solon/model/SaStorageForSolon.java | 6 +-
.../solon/util/SaSolonOperateUtil.java} | 36 ++--
.../solon/util/SaTokenContextUtil.java | 85 ++++++++++
.../SaFirewallCheckFilterForServlet.java | 23 +--
.../dev33/satoken/filter/SaServletFilter.java | 39 ++---
.../SaTokenContextFilterForServlet.java | 46 ++++++
.../spring/SaTokenContextForSpring.java | 75 ---------
.../spring/SaTokenContextRegister.java | 29 ++--
...SpringBootVersionCompatibilityChecker.java | 2 +-
.../dev33/satoken/spring/SpringMVCUtil.java | 12 +-
...aFirewallCheckFilterForJakartaServlet.java | 22 +--
.../dev33/satoken/filter/SaServletFilter.java | 39 ++---
...SaTokenContextFilterForJakartaServlet.java | 46 ++++++
...TokenContextForSpringInJakartaServlet.java | 11 +-
.../spring/SaTokenContextRegister.java | 29 ++--
.../dev33/satoken/spring/SpringMVCUtil.java | 10 +-
92 files changed, 1538 insertions(+), 1234 deletions(-)
rename sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java => sa-token-core/src/main/java/cn/dev33/satoken/fun/SaRetGenericFunction.java (62%)
rename sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java => sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRouteMatchFunction.java (62%)
create mode 100644 sa-token-demo/sa-token-demo-webflux-springboot3/src/main/java/com/pj/test/UserService.java
delete mode 100644 sa-token-demo/sa-token-demo-webflux-springboot3/src/main/java/com/pj/util/AjaxJson.java
create mode 100644 sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/test/UserService.java
delete mode 100644 sa-token-demo/sa-token-demo-webflux/src/main/java/com/pj/util/AjaxJson.java
create mode 100644 sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaJakartaServletOperateUtil.java
create mode 100644 sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java
create mode 100644 sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java
create mode 100644 sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java
create mode 100644 sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java
create mode 100644 sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java
create mode 100644 sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaServletOperateUtil.java
create mode 100644 sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java
create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenContextFilterForSolon.java
rename sa-token-starter/{sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/error/SaSpringBootErrorCode.java => sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaSolonOperateUtil.java} (54%)
create mode 100644 sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaTokenContextUtil.java
create mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForServlet.java
delete mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpring.java
create mode 100644 sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.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 b24795e0..085a078e 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
@@ -22,6 +22,7 @@ import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.SaTokenContextDefaultImpl;
+import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
import cn.dev33.satoken.context.second.SaTokenSecondContext;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
@@ -155,9 +156,16 @@ public class SaManager {
SaTokenEventCenter.doRegisterComponent("SaTokenContext", saTokenContext);
}
public static SaTokenContext getSaTokenContext() {
+ if (saTokenContext == null) {
+ synchronized (SaManager.class) {
+ if (saTokenContext == null) {
+ SaManager.saTokenContext = new SaTokenContextForThreadLocal();
+ }
+ }
+ }
return saTokenContext;
}
-
+
/**
* 二级上下文 SaTokenSecondContext
*/
@@ -169,29 +177,29 @@ public class SaManager {
public static SaTokenSecondContext getSaTokenSecondContext() {
return saTokenSecondContext;
}
-
+
/**
* 获取一个可用的 SaTokenContext (按照一级上下文、二级上下文、默认上下文的顺序来判断)
- * @return /
+ * @return /
*/
public static SaTokenContext getSaTokenContextOrSecond() {
-
+
// s1. 一级Context可用时返回一级Context
if(saTokenContext != null) {
if(saTokenSecondContext == null || saTokenContext.isValid()) {
- // 因为 isValid 是一个耗时操作,所以此处假定:二级Context为null的情况下无需验证一级Context有效性
- // 这样可以提升6倍左右的上下文获取速度
+ // 因为 isValid 是一个耗时操作,所以此处假定:二级Context为null的情况下无需验证一级Context有效性
+ // 这样可以提升6倍左右的上下文获取速度
return saTokenContext;
}
}
-
- // s2. 一级Context不可用时判断二级Context是否可用
+
+ // s2. 一级Context不可用时判断二级Context是否可用
if(saTokenSecondContext != null && saTokenSecondContext.isValid()) {
return saTokenSecondContext;
}
-
- // s3. 都不行,就返回默认的 Context
- return SaTokenContextDefaultImpl.defaultContext;
+
+ // s3. 都不行,就返回默认的 Context
+ return SaTokenContextDefaultImpl.defaultContext;
}
/**
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java
index 3bec3cbc..62ceedc8 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaHolder.java
@@ -36,7 +36,7 @@ public class SaHolder {
* @return /
*/
public static SaTokenContext getContext() {
- return SaManager.getSaTokenContextOrSecond();
+ return SaManager.getSaTokenContext();
}
/**
@@ -46,7 +46,7 @@ public class SaHolder {
* @return /
*/
public static SaRequest getRequest() {
- return SaManager.getSaTokenContextOrSecond().getRequest();
+ return SaManager.getSaTokenContext().getRequest();
}
/**
@@ -56,7 +56,7 @@ public class SaHolder {
* @return /
*/
public static SaResponse getResponse() {
- return SaManager.getSaTokenContextOrSecond().getResponse();
+ return SaManager.getSaTokenContext().getResponse();
}
/**
@@ -66,7 +66,7 @@ public class SaHolder {
* @return /
*/
public static SaStorage getStorage() {
- return SaManager.getSaTokenContextOrSecond().getStorage();
+ return SaManager.getSaTokenContext().getStorage();
}
/**
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContext.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContext.java
index 3682a0bc..fd3f7e79 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContext.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContext.java
@@ -16,8 +16,8 @@
package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
-import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.model.SaResponse;
+import cn.dev33.satoken.context.model.SaStorage;
/**
* Sa-Token 上下文处理器
@@ -53,20 +53,6 @@ public interface SaTokenContext {
*/
SaStorage getStorage();
- /**
- * 判断:指定路由匹配符是否可以匹配成功指定路径
- *
- * 判断规则由底层 web 框架决定,例如在 springboot 中:
- * - matchPath("/user/*", "/user/login") 返回: true
- * - matchPath("/user/*", "/article/edit") 返回: false
- *
- *
- * @param pattern 路由匹配符
- * @param path 需要匹配的路径
- * @return /
- */
- boolean matchPath(String pattern, String path);
-
/**
* 判断:在本次请求中,此上下文是否可用。
* 例如在部分 rpc 调用时, 一级上下文会返回 false,这时候框架就会选择使用二级上下文来处理请求
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextDefaultImpl.java
index 80991a4d..70cc0976 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextDefaultImpl.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextDefaultImpl.java
@@ -59,9 +59,4 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
- @Override
- public boolean matchPath(String pattern, String path) {
- throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
- }
-
}
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextForThreadLocal.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextForThreadLocal.java
index 7a9c3bc6..fd5395c1 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextForThreadLocal.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/SaTokenContextForThreadLocal.java
@@ -49,11 +49,6 @@ public class SaTokenContextForThreadLocal implements SaTokenContext {
return SaTokenContextForThreadLocalStorage.getStorage();
}
- @Override
- public boolean matchPath(String pattern, String path) {
- return false;
- }
-
@Override
public boolean isValid() {
return SaTokenContextForThreadLocalStorage.getBox() != null;
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/error/SaErrorCode.java b/sa-token-core/src/main/java/cn/dev33/satoken/error/SaErrorCode.java
index a69af4b8..946fc88a 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/error/SaErrorCode.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/error/SaErrorCode.java
@@ -227,4 +227,9 @@ public interface SaErrorCode {
/** API Key 不属于指定用户 */
int CODE_12312 = 12312;
+ // ------------
+
+ /** 未实现具体的路由匹配策略 */
+ int CODE_12401 = 12401;
+
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java b/sa-token-core/src/main/java/cn/dev33/satoken/fun/SaRetGenericFunction.java
similarity index 62%
rename from sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java
rename to sa-token-core/src/main/java/cn/dev33/satoken/fun/SaRetGenericFunction.java
index dccfffb6..327d0b48 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/fun/SaRetGenericFunction.java
@@ -13,23 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package cn.dev33.satoken.reactor.error;
+package cn.dev33.satoken.fun;
/**
- * 定义 sa-token-reactor-spring-boot-starter 所有异常细分状态码
- *
+ * 无形参、有返回值(泛型)的函数式接口,方便开发者进行 lambda 表达式风格调用
+ *
* @author click33
- * @since 1.33.0
+ * @since 1.42.0
*/
-public interface SaReactorSpringBootErrorCode {
+@FunctionalInterface
+public interface SaRetGenericFunction {
+
+ /**
+ * 执行的方法
+ * @return 返回值
+ */
+ T run();
- /** 对象转 JSON 字符串失败 */
- int CODE_20203 = 20203;
-
- /** JSON 字符串转 Map 失败 */
- int CODE_20204 = 20204;
-
- /** 默认的 Filter 异常处理函数 */
- int CODE_20205 = 20205;
-
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRouteMatchFunction.java
similarity index 62%
rename from sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java
rename to sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRouteMatchFunction.java
index c9e1378a..aa6aba28 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/error/SaReactorSpringBootErrorCode.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRouteMatchFunction.java
@@ -13,23 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package cn.dev33.satoken.reactor.error;
+package cn.dev33.satoken.fun.strategy;
+
+import java.util.function.BiFunction;
/**
- * 定义 sa-token-reactor3-spring-boot-starter 所有异常细分状态码
- *
+ * 函数式接口:路由匹配策略
+ *
+ * 参数:pattern, path
+ * 返回:是否匹配
+ *
* @author click33
- * @since 1.34.0
+ * @since 1.42.0
*/
-public interface SaReactorSpringBootErrorCode {
-
- /** 对象转 JSON 字符串失败 */
- int CODE_20203 = 20203;
+@FunctionalInterface
+public interface SaRouteMatchFunction extends BiFunction {
- /** JSON 字符串转 Map 失败 */
- int CODE_20204 = 20204;
-
- /** 默认的 Filter 异常处理函数 */
- int CODE_20205 = 20205;
-
-}
+}
\ No newline at end of file
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/router/SaRouter.java b/sa-token-core/src/main/java/cn/dev33/satoken/router/SaRouter.java
index 99002a3e..0d452831 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/router/SaRouter.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/router/SaRouter.java
@@ -15,15 +15,15 @@
*/
package cn.dev33.satoken.router;
-import java.util.List;
-
-import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.fun.SaFunction;
import cn.dev33.satoken.fun.SaParamFunction;
import cn.dev33.satoken.fun.SaParamRetFunction;
+import cn.dev33.satoken.strategy.SaStrategy;
+
+import java.util.List;
/**
* 路由匹配操作工具类
@@ -55,7 +55,7 @@ public class SaRouter {
* @return 是否匹配成功
*/
public static boolean isMatch(String pattern, String path) {
- return SaManager.getSaTokenContextOrSecond().matchPath(pattern, path);
+ return SaStrategy.instance.routeMatcher.apply(pattern, path);
}
/**
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 5e461a73..09726fbc 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
@@ -16,6 +16,8 @@
package cn.dev33.satoken.strategy;
import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.error.SaErrorCode;
+import cn.dev33.satoken.exception.NotImplException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.fun.strategy.*;
import cn.dev33.satoken.session.SaSession;
@@ -175,6 +177,13 @@ public final class SaStrategy {
return new StpLogic(loginType);
};
+ /**
+ * 路由匹配策略
+ */
+ public SaRouteMatchFunction routeMatcher = (pattern, path) -> {
+ throw new NotImplException("未实现具体路由匹配策略").setCode(SaErrorCode.CODE_12401);
+ };
+
// ----------------------- 重写策略 set连缀风格
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java
index fcbb6307..bca48cd3 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaTokenConsts.java
@@ -194,7 +194,17 @@ public class SaTokenConsts {
/**
* 防火墙校验过滤器的注册顺序
*/
- public static final int FIREWALL_CHECK_FILTER_ORDER = -1000;
+ public static final int FIREWALL_CHECK_FILTER_ORDER = -102;
+
+ /**
+ * 跨域处理过滤器的注册顺序
+ */
+ public static final int CORS_FILTER_ORDER = -103;
+
+ /**
+ * 上下文过滤器的注册顺序
+ */
+ public static final int SA_TOKEN_CONTEXT_FILTER_ORDER = -104;
/**
* Content-Type key
diff --git a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java
index 8bc72dfa..43ec18b7 100644
--- a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java
+++ b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/SaTokenDemoApp.java
@@ -17,4 +17,5 @@ public class SaTokenDemoApp {
Solon.start(SaTokenDemoApp.class, args);
System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
}
+
}
\ No newline at end of file
diff --git a/sa-token-demo/sa-token-demo-springboot3-redis/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-springboot3-redis/src/main/java/com/pj/test/TestController.java
index fc6d1844..b9f11ead 100644
--- a/sa-token-demo/sa-token-demo-springboot3-redis/src/main/java/com/pj/test/TestController.java
+++ b/sa-token-demo/sa-token-demo-springboot3-redis/src/main/java/com/pj/test/TestController.java
@@ -1,6 +1,7 @@
package com.pj.test;
import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.servlet.util.SaTokenContextUtil;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -18,7 +19,9 @@ public class TestController {
// 测试 浏览器访问: http://localhost:8081/test/test
@RequestMapping("test")
public SaResult test() {
- System.out.println("------------进来了");
+ System.out.println("------------进来了");
+ System.out.println(SpringMVCUtil.getRequest());
+ System.out.println(SaTokenContextUtil.getRequest());
return SaResult.ok();
}
diff --git a/sa-token-demo/sa-token-demo-test/pom.xml b/sa-token-demo/sa-token-demo-test/pom.xml
index dac828ca..e128b06b 100644
--- a/sa-token-demo/sa-token-demo-test/pom.xml
+++ b/sa-token-demo/sa-token-demo-test/pom.xml
@@ -73,8 +73,12 @@
spring-boot-configuration-processor
true
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
-
+
diff --git a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/Test2Controller.java b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/Test2Controller.java
index 24e0c033..faea0641 100644
--- a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/Test2Controller.java
+++ b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/Test2Controller.java
@@ -1,6 +1,7 @@
package com.pj.test;
-import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.servlet.util.SaTokenContextUtil;
+import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -17,9 +18,12 @@ public class Test2Controller {
@RequestMapping("/test")
public SaResult test2() {
- StpUtil.login(30003);
- System.out.println(StpUtil.getSession().timeout());
- System.out.println(StpUtil.getStpLogic().getTokenSession(false));
+ System.out.println(SpringMVCUtil.getRequest());
+ System.out.println(SaTokenContextUtil.getRequest());
+
+// StpUtil.login(30003);
+// System.out.println(StpUtil.getSession().timeout());
+// System.out.println(StpUtil.getStpLogic().getTokenSession(false));
return SaResult.ok();
}
diff --git a/sa-token-demo/sa-token-demo-webflux-springboot3/pom.xml b/sa-token-demo/sa-token-demo-webflux-springboot3/pom.xml
index 262e149e..823ade1f 100644
--- a/sa-token-demo/sa-token-demo-webflux-springboot3/pom.xml
+++ b/sa-token-demo/sa-token-demo-webflux-springboot3/pom.xml
@@ -26,10 +26,6 @@
org.springframework.boot
spring-boot-starter-webflux
-
- org.springframework.boot
- spring-boot-starter-aop
-
@@ -37,21 +33,14 @@
sa-token-reactor-spring-boot3-starter
${sa-token.version}
-
-
+
+
-
-
-
-
+
cn.dev33
@@ -38,20 +34,13 @@
${sa-token.version}
-
+
-
-
-
-
+
2.7.18
3.4.3
- 3.1.4.RELEASE
+ 5.3.39
+ 3.7.4
2.13.4.1
2.11.2
3.1.0
diff --git a/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/SaTokenSecondContextForDubbo.java b/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/SaTokenSecondContextForDubbo.java
index c6dfa03f..90c6dee0 100644
--- a/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/SaTokenSecondContextForDubbo.java
+++ b/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/SaTokenSecondContextForDubbo.java
@@ -15,8 +15,6 @@
*/
package cn.dev33.satoken.context.dubbo;
-import org.apache.dubbo.rpc.RpcContext;
-
import cn.dev33.satoken.context.dubbo.model.SaRequestForDubbo;
import cn.dev33.satoken.context.dubbo.model.SaResponseForDubbo;
import cn.dev33.satoken.context.dubbo.model.SaStorageForDubbo;
@@ -24,7 +22,7 @@ import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.second.SaTokenSecondContext;
-import cn.dev33.satoken.exception.ApiDisabledException;
+import org.apache.dubbo.rpc.RpcContext;
/**
* Sa-Token 二级上下文 [ Dubbo版本 ]
@@ -49,11 +47,6 @@ public class SaTokenSecondContextForDubbo implements SaTokenSecondContext {
return new SaStorageForDubbo(RpcContext.getContext());
}
- @Override
- public boolean matchPath(String pattern, String path) {
- throw new ApiDisabledException();
- }
-
@Override
public boolean isValid() {
return RpcContext.getContext() != null;
diff --git a/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/filter/SaTokenDubboConsumerFilter.java b/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/filter/SaTokenDubboConsumerFilter.java
index 15aacb60..702372b7 100644
--- a/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/filter/SaTokenDubboConsumerFilter.java
+++ b/sa-token-plugin/sa-token-dubbo/src/main/java/cn/dev33/satoken/context/dubbo/filter/SaTokenDubboConsumerFilter.java
@@ -48,7 +48,7 @@ public class SaTokenDubboConsumerFilter implements Filter {
}
// 2、调用前,向下传递会话Token
- if(SaManager.getSaTokenContextOrSecond() != SaTokenContextDefaultImpl.defaultContext) {
+ if(SaManager.getSaTokenContext() != SaTokenContextDefaultImpl.defaultContext) {
RpcContext.getContext().setAttachment(SaTokenConsts.JUST_CREATED, StpUtil.getTokenValueNotCut());
}
diff --git a/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/SaTokenSecondContextForDubbo3.java b/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/SaTokenSecondContextForDubbo3.java
index bd43ab98..d05ace84 100644
--- a/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/SaTokenSecondContextForDubbo3.java
+++ b/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/SaTokenSecondContextForDubbo3.java
@@ -22,7 +22,6 @@ import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.second.SaTokenSecondContext;
-import cn.dev33.satoken.exception.ApiDisabledException;
import org.apache.dubbo.rpc.RpcContext;
/**
@@ -48,11 +47,6 @@ public class SaTokenSecondContextForDubbo3 implements SaTokenSecondContext {
return new SaStorageForDubbo3(RpcContext.getServiceContext());
}
- @Override
- public boolean matchPath(String pattern, String path) {
- throw new ApiDisabledException();
- }
-
@Override
public boolean isValid() {
return RpcContext.getServiceContext() != null;
diff --git a/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/filter/SaTokenDubbo3ConsumerFilter.java b/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/filter/SaTokenDubbo3ConsumerFilter.java
index b54b48f7..83dce1ac 100644
--- a/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/filter/SaTokenDubbo3ConsumerFilter.java
+++ b/sa-token-plugin/sa-token-dubbo3/src/main/java/cn/dev33/satoken/context/dubbo3/filter/SaTokenDubbo3ConsumerFilter.java
@@ -42,7 +42,7 @@ public class SaTokenDubbo3ConsumerFilter implements Filter {
}
// 1. 调用前,向下传递会话Token
- if(SaManager.getSaTokenContextOrSecond() != SaTokenContextDefaultImpl.defaultContext) {
+ if(SaManager.getSaTokenContext() != SaTokenContextDefaultImpl.defaultContext) {
RpcContext.getServiceContext().setAttachment(SaTokenConsts.JUST_CREATED, StpUtil.getTokenValueNotCut());
}
diff --git a/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/SaTokenSecondContextForGrpc.java b/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/SaTokenSecondContextForGrpc.java
index 729fd9d8..47f6d8c5 100644
--- a/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/SaTokenSecondContextForGrpc.java
+++ b/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/SaTokenSecondContextForGrpc.java
@@ -23,7 +23,6 @@ import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.second.SaTokenSecondContext;
-import cn.dev33.satoken.exception.ApiDisabledException;
/**
* Sa-Token 上下文 [grpc版本]
@@ -48,11 +47,6 @@ public class SaTokenSecondContextForGrpc implements SaTokenSecondContext {
return new SaStorageForGrpc();
}
- @Override
- public boolean matchPath(String pattern, String path) {
- throw new ApiDisabledException();
- }
-
@Override
public boolean isValid() {
return SaTokenGrpcContext.isNotNull();
diff --git a/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/interceptor/SaTokenGrpcClientInterceptor.java b/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/interceptor/SaTokenGrpcClientInterceptor.java
index 5a2dee19..040e9f12 100644
--- a/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/interceptor/SaTokenGrpcClientInterceptor.java
+++ b/sa-token-plugin/sa-token-grpc/src/main/java/cn/dev33/satoken/context/grpc/interceptor/SaTokenGrpcClientInterceptor.java
@@ -58,7 +58,7 @@ public class SaTokenGrpcClientInterceptor implements ClientInterceptor, Ordered
// 调用前,传递会话Token
String tokenValue = StpUtil.getTokenValue();
if (SaFoxUtil.isNotEmpty(tokenValue)
- && SaManager.getSaTokenContextOrSecond() != SaTokenContextDefaultImpl.defaultContext) {
+ && SaManager.getSaTokenContext() != SaTokenContextDefaultImpl.defaultContext) {
headers.put(GrpcContextConstants.SA_JUST_CREATED_NOT_PREFIX, tokenValue);
}
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 ca6250a3..f65d569b 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
@@ -188,7 +188,7 @@ public class SaRequestForServlet implements SaRequest {
@Override
public Object forward(String path) {
try {
- HttpServletResponse response = (HttpServletResponse)SaManager.getSaTokenContextOrSecond().getResponse().getSource();
+ HttpServletResponse response = (HttpServletResponse)SaManager.getSaTokenContext().getResponse().getSource();
request.getRequestDispatcher(path).forward(request, response);
return null;
} catch (ServletException | IOException e) {
diff --git a/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaJakartaServletOperateUtil.java b/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaJakartaServletOperateUtil.java
new file mode 100644
index 00000000..eb126491
--- /dev/null
+++ b/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaJakartaServletOperateUtil.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.servlet.util;
+
+import cn.dev33.satoken.util.SaTokenConsts;
+import jakarta.servlet.ServletResponse;
+
+import java.io.IOException;
+
+/**
+ * Jakarta Servlet 操作工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaJakartaServletOperateUtil {
+
+ /**
+ * 写入结果到输出流
+ * @param response /
+ * @param result /
+ */
+ public static void writeResult(ServletResponse response, String result) throws IOException {
+ // 写入输出流
+ // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
+ // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
+ if(response.getContentType() == null) {
+ response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
+ }
+ response.getWriter().print(result);
+ response.getWriter().flush();
+ }
+
+
+}
diff --git a/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java b/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java
new file mode 100644
index 00000000..7908f8a8
--- /dev/null
+++ b/sa-token-starter/sa-token-jakarta-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.servlet.util;
+
+import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage;
+import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage.Box;
+import cn.dev33.satoken.context.model.SaRequest;
+import cn.dev33.satoken.context.model.SaResponse;
+import cn.dev33.satoken.context.model.SaStorage;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.servlet.model.SaRequestForServlet;
+import cn.dev33.satoken.servlet.model.SaResponseForServlet;
+import cn.dev33.satoken.servlet.model.SaStorageForServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+
+/**
+ * SaTokenContext 上下文读写工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaTokenContextUtil {
+
+ /**
+ * 写入当前上下文
+ * @param request /
+ * @param response /
+ */
+ public static void setContext(HttpServletRequest request, HttpServletResponse response) {
+ SaRequest req = new SaRequestForServlet(request);
+ SaResponse res = new SaResponseForServlet(response);
+ SaStorage stg = new SaStorageForServlet(request);
+ SaTokenContextForThreadLocalStorage.setBox(req, res, stg);
+ }
+
+ /**
+ * 清除当前上下文
+ */
+ public static void clearContext() {
+ SaTokenContextForThreadLocalStorage.clearBox();
+ }
+
+ /**
+ * 写入上下文对象, 并在执行函数后将其清除
+ * @param request /
+ * @param response /
+ * @param fun /
+ */
+ public static void setContext(HttpServletRequest request, HttpServletResponse response, SaFunction fun) {
+ try {
+ setContext(request, response);
+ fun.run();
+ } finally {
+ clearContext();
+ }
+ }
+
+ /**
+ * 获取当前 Box
+ * @return /
+ */
+ public static Box getBox() {
+ return SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ }
+
+ /**
+ * 获取当前 Request
+ * @return /
+ */
+ public static HttpServletRequest getRequest() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (HttpServletRequest) box.getRequest().getSource();
+ }
+
+ /**
+ * 获取当前 Response
+ * @return /
+ */
+ public static HttpServletResponse getResponse() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (HttpServletResponse) box.getResponse().getSource();
+ }
+
+}
diff --git a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenContextForJboot.java b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenContextForJboot.java
index 253b8e88..974541f3 100644
--- a/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenContextForJboot.java
+++ b/sa-token-starter/sa-token-jboot-plugin/src/main/java/cn/dev33/satoken/jboot/SaTokenContextForJboot.java
@@ -22,12 +22,21 @@ import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
+import cn.dev33.satoken.strategy.SaStrategy;
import io.jboot.web.controller.JbootControllerContext;
/**
* Sa-Token 上线文处理器 [Jboot 版本实现]
*/
public class SaTokenContextForJboot implements SaTokenContext {
+
+ public SaTokenContextForJboot() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return PathAnalyzer.get(pattern).matches(path);
+ };
+ }
+
/**
* 获取当前请求的Request对象
*/
@@ -52,14 +61,6 @@ public class SaTokenContextForJboot implements SaTokenContext {
return new SaStorageForServlet(JbootControllerContext.get().getRequest());
}
- /**
- * 校验指定路由匹配符是否可以匹配成功指定路径
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return PathAnalyzer.get(pattern).matches(path);
- }
-
@Override
public boolean isValid() {
return SaTokenContext.super.isValid();
diff --git a/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenContextForJfinal.java b/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenContextForJfinal.java
index 6b5412cb..198137a4 100644
--- a/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenContextForJfinal.java
+++ b/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenContextForJfinal.java
@@ -22,11 +22,20 @@ import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
+import cn.dev33.satoken.strategy.SaStrategy;
/**
* Sa-Token 上线文处理器 [Jfinal 版本实现]
*/
public class SaTokenContextForJfinal implements SaTokenContext {
+
+ public SaTokenContextForJfinal() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return PathAnalyzer.get(pattern).matches(path);
+ };
+ }
+
/**
* 获取当前请求的Request对象
*/
@@ -51,14 +60,6 @@ public class SaTokenContextForJfinal implements SaTokenContext {
return new SaStorageForServlet(SaControllerContext.get().getRequest());
}
- /**
- * 校验指定路由匹配符是否可以匹配成功指定路径
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return PathAnalyzer.get(pattern).matches(path);
- }
-
@Override
public boolean isValid() {
return SaTokenContext.super.isValid();
diff --git a/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenPathFilter.java b/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenPathFilter.java
index df5d380d..47ce1087 100644
--- a/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenPathFilter.java
+++ b/sa-token-starter/sa-token-jfinal-plugin/src/main/java/cn/dev33/satoken/jfinal/SaTokenPathFilter.java
@@ -16,9 +16,9 @@
package cn.dev33.satoken.jfinal;
import cn.dev33.satoken.exception.SaTokenException;
+import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
-import cn.dev33.satoken.filter.SaFilter;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml b/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml
index 72101e93..d61cd5c9 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/pom.xml
@@ -23,7 +23,7 @@
spring-boot-starter
true
-
+
org.springframework
@@ -31,11 +31,10 @@
true
-
+
io.projectreactor
reactor-core
- true
@@ -51,36 +50,25 @@
spring-boot-configuration-processor
true
-
-
-
- cn.dev33
- sa-token-core
-
-
+
cn.dev33
sa-token-spring-boot-autoconfig
-
-
+
-
+
org.springframework
spring-web
- 5.3.7
+ 5.3.39
-
+
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java
index c03ea589..2c9db4cc 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java
@@ -15,9 +15,12 @@
*/
package cn.dev33.satoken.reactor.context;
+import cn.dev33.satoken.fun.SaRetGenericFunction;
import org.springframework.web.server.ServerWebExchange;
-
+import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
+import reactor.util.context.Context;
+import reactor.util.context.ContextView;
/**
* Reactor 上下文操作(异步),持有当前请求的 ServerWebExchange 全局引用
@@ -28,37 +31,67 @@ import reactor.core.publisher.Mono;
public class SaReactorHolder {
/**
- * key
+ * ServerWebExchange key
*/
- public static final Class CONTEXT_KEY = ServerWebExchange.class;
+ public static final String EXCHANGE_KEY = "SA_REACTOR_EXCHANGE_KEY";
/**
- * chain_key
+ * WebFilterChain key
*/
- public static final String CHAIN_KEY = "WEB_FILTER_CHAIN_KEY";
-
+ public static final String CHAIN_KEY = "SA_REACTOR__CHAIN_KEY";
+
/**
- * 获取上下文对象
- * @return see note
+ * 在流式上下文写入 ServerWebExchange
+ * @param ctx 必填
+ * @param exchange 必填
+ * @param chain 非必填
+ * @return /
*/
- public static Mono getContext() {
- // 从全局 Mono 获取
- return Mono.subscriberContext().map(ctx -> ctx.get(CONTEXT_KEY));
+ public static Context setContext(Context ctx, ServerWebExchange exchange, WebFilterChain chain) {
+ return ctx
+ .put(EXCHANGE_KEY, exchange)
+ .put(CHAIN_KEY, chain);
}
-
+
/**
- * 获取上下文对象, 并设置到同步上下文中
- * @return see note
+ * 在流式上下文获取 ServerWebExchange
+ * @param ctx /
+ * @return /
*/
- public static Mono getContextAndSetSync() {
- // 从全局 Mono 获取
- return Mono.subscriberContext().map(ctx -> {
- // 设置到sync中
- SaReactorSyncHolder.setContext(ctx.get(CONTEXT_KEY));
- return ctx.get(CONTEXT_KEY);
- }).doFinally(r->{
- // 从sync中清除
- SaReactorSyncHolder.clearContext();
+ public static ServerWebExchange getExchange(ContextView ctx) {
+ return ctx.get(EXCHANGE_KEY);
+ }
+
+ /**
+ * 在流式上下文获取 WebFilterChain
+ * @param ctx /
+ * @return /
+ */
+ public static WebFilterChain getChain(ContextView ctx) {
+ return ctx.get(CHAIN_KEY);
+ }
+
+ /**
+ * 获取 Mono < ServerWebExchange >
+ * @return /
+ */
+ public static Mono getMonoExchange() {
+ return Mono.deferContextual(ctx -> Mono.just(getExchange(ctx)));
+ }
+
+ /**
+ * 将 exchange 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
+ *
+ * @return /
+ */
+ public static Mono sync(SaRetGenericFunction fun) {
+ return Mono.deferContextual(ctx -> {
+ try {
+ SaReactorSyncHolder.setContext(ctx.get(EXCHANGE_KEY));
+ return Mono.just(fun.run());
+ } finally {
+ SaReactorSyncHolder.clearContext();
+ }
});
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java
index 4487ab16..62666f1b 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java
@@ -15,17 +15,16 @@
*/
package cn.dev33.satoken.reactor.context;
-import org.springframework.web.server.ServerWebExchange;
-
import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage;
import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage.Box;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
-import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.fun.SaRetGenericFunction;
import cn.dev33.satoken.reactor.model.SaRequestForReactor;
import cn.dev33.satoken.reactor.model.SaResponseForReactor;
import cn.dev33.satoken.reactor.model.SaStorageForReactor;
+import org.springframework.web.server.ServerWebExchange;
/**
* Reactor上下文操作(同步),持有当前请求的 ServerWebExchange 全局引用
@@ -36,8 +35,8 @@ import cn.dev33.satoken.reactor.model.SaStorageForReactor;
public class SaReactorSyncHolder {
/**
- * 写入上下文对象
- * @param exchange see note
+ * 在同步上下文写入 ServerWebExchange
+ * @param exchange /
*/
public static void setContext(ServerWebExchange exchange) {
SaRequest request = new SaRequestForReactor(exchange.getRequest());
@@ -45,32 +44,32 @@ public class SaReactorSyncHolder {
SaStorage storage = new SaStorageForReactor(exchange);
SaTokenContextForThreadLocalStorage.setBox(request, response, storage);
}
-
+
/**
- * 获取上下文对象
- * @return see note
- */
- public static ServerWebExchange getContext() {
- Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
- return (ServerWebExchange)box.getStorage().getSource();
- }
-
- /**
- * 清除上下文对象
+ * 在同步上下文清除 ServerWebExchange
*/
public static void clearContext() {
SaTokenContextForThreadLocalStorage.clearBox();
}
-
+
/**
- * 写入上下文对象, 并在执行函数后将其清除
- * @param exchange see note
- * @param fun see note
+ * 在同步上下文获取 ServerWebExchange
+ * @return /
*/
- public static void setContext(ServerWebExchange exchange, SaFunction fun) {
+ public static ServerWebExchange getExchange() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (ServerWebExchange)box.getStorage().getSource();
+ }
+
+ /**
+ * 将 exchange 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
+ * @param exchange /
+ * @param fun /
+ */
+ public static R setContext(ServerWebExchange exchange, SaRetGenericFunction fun) {
try {
setContext(exchange);
- fun.run();
+ return fun.run();
} finally {
clearContext();
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java
index cef0a73b..52a4b091 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java
@@ -15,10 +15,13 @@
*/
package cn.dev33.satoken.reactor.filter;
+import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.FirewallCheckException;
import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.model.SaRequestForReactor;
import cn.dev33.satoken.reactor.model.SaResponseForReactor;
+import cn.dev33.satoken.reactor.util.SaReactorOperateUtil;
import cn.dev33.satoken.strategy.SaFirewallStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
@@ -43,21 +46,25 @@ public class SaFirewallCheckFilterForReactor implements WebFilter {
SaResponseForReactor saResponse = new SaResponseForReactor(exchange.getResponse());
try {
+ SaReactorSyncHolder.setContext(exchange);
SaFirewallStrategy.instance.check.execute(saRequest, saResponse, exchange);
}
- catch (StopMatchException e) {
- // 如果是 StopMatchException 异常,代表通过了防火墙验证,进入 Controller
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
}
+ // FirewallCheckException 异常则交由异常处理策略处理
catch (FirewallCheckException e) {
- // FirewallCheckException 异常则交由异常处理策略处理
if(SaFirewallStrategy.instance.checkFailHandle == null) {
- exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
- return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(e.getMessage().getBytes())));
+ return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
} else {
SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
return Mono.empty();
}
}
+ finally {
+ SaReactorSyncHolder.clearContext();
+ }
// 更多异常则不处理,交由 Web 框架处理
// 向下执行
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java
index 8d501e25..ac5e5e9e 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java
@@ -21,9 +21,8 @@ import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
-import cn.dev33.satoken.reactor.context.SaReactorHolder;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
-import cn.dev33.satoken.reactor.error.SaReactorSpringBootErrorCode;
+import cn.dev33.satoken.reactor.util.SaReactorOperateUtil;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
@@ -37,7 +36,7 @@ import java.util.Arrays;
import java.util.List;
/**
- * Reactor 全局鉴权过滤器
+ * 全局鉴权过滤器 (基于 Reactor)
*
* 默认优先级为 -100,尽量保证在其它过滤器之前执行
*
@@ -103,7 +102,7 @@ public class SaReactorFilter implements SaFilter, WebFilter {
* 异常处理函数:每次[认证函数]发生异常时执行此函数
*/
public SaFilterErrorStrategy error = e -> {
- throw new SaTokenException(e).setCode(SaReactorSpringBootErrorCode.CODE_20205);
+ throw new SaTokenException(e);
};
/**
@@ -135,55 +134,25 @@ public class SaReactorFilter implements SaFilter, WebFilter {
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
-
- // 写入WebFilterChain对象
- exchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);
-
+
// ---------- 全局认证处理
try {
- // 写入全局上下文 (同步)
SaReactorSyncHolder.setContext(exchange);
-
- // 执行全局过滤器
beforeAuth.run(null);
- SaRouter.match(includeList).notMatch(excludeList).check(r -> {
- auth.run(null);
- });
-
- } catch (StopMatchException e) {
- // StopMatchException 异常代表:停止匹配,进入Controller
-
- } catch (Throwable e) {
- // 1. 获取异常处理策略结果
- String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
-
- // 2. 写入输出流
- // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
- // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
- if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
- exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
- }
- return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
-
- } finally {
- // 清除上下文
+ SaRouter.match(includeList).notMatch(excludeList).check(r -> auth.run(null));
+ }
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
+ }
+ catch (Throwable e) {
+ return SaReactorOperateUtil.writeResult(exchange, String.valueOf(error.run(e)));
+ }
+ finally {
SaReactorSyncHolder.clearContext();
}
- // ---------- 执行
-
- // 写入全局上下文 (同步)
- SaReactorSyncHolder.setContext(exchange);
-
- // 执行
- return chain.filter(exchange).subscriberContext(ctx -> {
- // 写入全局上下文 (异步)
- ctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);
- return ctx;
- }).doFinally(r -> {
- // 清除上下文
- SaReactorSyncHolder.clearContext();
- });
+ return chain.filter(exchange);
}
-
+
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java
new file mode 100644
index 00000000..7fb415bb
--- /dev/null
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.reactor.filter;
+
+import cn.dev33.satoken.reactor.context.SaReactorHolder;
+import cn.dev33.satoken.util.SaTokenConsts;
+import org.springframework.core.annotation.Order;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+/**
+ * SaTokenContext 上下文初始化过滤器 (基于 Reactor)
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+@Order(SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
+public class SaTokenContextFilterForReactor implements WebFilter {
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+ return chain.filter(exchange)
+ .contextWrite(ctx -> SaReactorHolder.setContext(ctx, exchange, chain))
+ .doFinally(r -> {
+ // 在流式上下文中保存的数据会随着流式操作的结束而销毁,所以此处无需手动清除数据
+ });
+ }
+
+}
+
+
+ /*
+ * 这种写法有问题:
+ @Override
+ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+ try {
+ SaReactorSyncHolder.setContext(exchange);
+ return chain.filter(exchange);
+ } finally {
+ SaReactorSyncHolder.clearContext();
+ }
+ }
+ 这种写法会先执行 finally,然后进入具体的 Controller
+ */
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 98b4c6ea..bc1a3558 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
@@ -184,7 +184,7 @@ public class SaRequestForReactor implements SaRequest {
*/
@Override
public Object forward(String path) {
- ServerWebExchange exchange = SaReactorSyncHolder.getContext();
+ ServerWebExchange exchange = SaReactorSyncHolder.getExchange();
WebFilterChain chain = exchange.getAttribute(SaReactorHolder.CHAIN_KEY);
ServerHttpRequest newRequest = request.mutate().path(path).build();
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java
index 82263785..46de9bcb 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java
@@ -16,22 +16,15 @@
package cn.dev33.satoken.reactor.spring;
import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
-import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
/**
+ * 此为低版本(<1.42.0) 的上下文处理方案,仅做留档,如无必要请勿使用
+ *
* Sa-Token 上下文处理器 [ Spring Reactor 版本实现 ] ,基于 SaTokenContextForThreadLocal 定制
*
* @author click33
* @since 1.33.0
*/
public class SaTokenContextForSpringReactor extends SaTokenContextForThreadLocal {
-
- /**
- * 重写路由匹配方法
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return SaPathPatternParserUtil.match(pattern, path);
- }
-
+
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java
index 8d259b73..d5561274 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java
@@ -16,10 +16,11 @@
package cn.dev33.satoken.reactor.spring;
import cn.dev33.satoken.reactor.filter.SaFirewallCheckFilterForReactor;
+import cn.dev33.satoken.reactor.filter.SaTokenContextFilterForReactor;
+import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
+import cn.dev33.satoken.strategy.SaStrategy;
import org.springframework.context.annotation.Bean;
-import cn.dev33.satoken.context.SaTokenContext;
-
/**
* 注册 Sa-Token 所需要的 Bean
*
@@ -28,18 +29,25 @@ import cn.dev33.satoken.context.SaTokenContext;
*/
public class SaTokenContextRegister {
- /**
- * 获取上下文处理器组件 (Spring Reactor 版)
- *
- * @return /
- */
- @Bean
- public SaTokenContext getSaTokenContextForSpringReactor() {
- return new SaTokenContextForSpringReactor();
+ public SaTokenContextRegister() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return SaPathPatternParserUtil.match(pattern, path);
+ };
}
/**
- * 请求 path 校验过滤器
+ * 上下文过滤器
+ *
+ * @return /
+ */
+ @Bean
+ public SaTokenContextFilterForReactor saTokenContextFilterForServlet() {
+ return new SaTokenContextFilterForReactor();
+ }
+
+ /**
+ * 防火墙过滤器
*
* @return /
*/
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SpringBootVersionCompatibilityChecker.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SpringBootVersionCompatibilityChecker.java
index 266fa7e4..8afcf09a 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SpringBootVersionCompatibilityChecker.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SpringBootVersionCompatibilityChecker.java
@@ -5,7 +5,7 @@ import cn.dev33.satoken.util.SaFoxUtil;
import org.springframework.boot.SpringBootVersion;
/**
- * SpringBoot 版本与 Sa-Token 版本兼容检查器
+ * SpringBoot 版本与 Sa-Token 版本兼容检查器,当开发者错误的在 SpringBoot3.x 项目中引入当前集成包时,将在控制台做出提醒并阻断项目启动
*
* @author Uncarbon
* @since 1.38.0
@@ -22,4 +22,5 @@ public class SpringBootVersionCompatibilityChecker {
System.err.println(str);
throw new SaTokenException(str);
}
+
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java
new file mode 100644
index 00000000..706501bf
--- /dev/null
+++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.reactor.util;
+
+import cn.dev33.satoken.util.SaTokenConsts;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * Reactor 操作工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaReactorOperateUtil {
+
+ /**
+ * 写入结果到输出流
+ * @param exchange /
+ * @param result /
+ * @return /
+ */
+ public static Mono writeResult(ServerWebExchange exchange, String result) {
+ // 写入输出流
+ // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
+ // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
+ if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
+ exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
+ }
+ return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
+ }
+
+}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/pom.xml b/sa-token-starter/sa-token-reactor-spring-boot3-starter/pom.xml
index 40ed07c1..0c13412b 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/pom.xml
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/pom.xml
@@ -32,15 +32,13 @@
org.springframework
spring-web
-
true
-
+
io.projectreactor
reactor-core
- true
@@ -56,24 +54,13 @@
spring-boot-configuration-processor
true
-
-
-
- cn.dev33
- sa-token-core
-
-
+
cn.dev33
sa-token-spring-boot-autoconfig
-
-
+
@@ -85,25 +72,19 @@
spring-boot-starter
${springboot3.version}
-
+
org.springframework
spring-web
- 6.0.0
+ 6.2.5
-
-
- io.projectreactor
- reactor-core
- 3.5.1
-
-
+
-
+
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java
index de66935e..6f81609c 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorHolder.java
@@ -15,50 +15,83 @@
*/
package cn.dev33.satoken.reactor.context;
+import cn.dev33.satoken.fun.SaRetGenericFunction;
import org.springframework.web.server.ServerWebExchange;
-
+import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
+import reactor.util.context.Context;
+import reactor.util.context.ContextView;
/**
* Reactor 上下文操作(异步),持有当前请求的 ServerWebExchange 全局引用
*
* @author click33
- * @since 1.34.0
+ * @since 1.19.0
*/
public class SaReactorHolder {
-
- /**
- * key
- */
- public static final Class CONTEXT_KEY = ServerWebExchange.class;
/**
- * chain_key
+ * ServerWebExchange key
*/
- public static final String CHAIN_KEY = "WEB_FILTER_CHAIN_KEY";
-
+ public static final String EXCHANGE_KEY = "SA_REACTOR_EXCHANGE_KEY";
+
/**
- * 获取上下文对象
- * @return see note
+ * WebFilterChain key
*/
- public static Mono getContext() {
- // 从全局 Mono 获取
- return Mono.deferContextual(Mono::just).map(ctx -> ctx.get(CONTEXT_KEY));
+ public static final String CHAIN_KEY = "SA_REACTOR__CHAIN_KEY";
+
+ /**
+ * 在流式上下文写入 ServerWebExchange
+ * @param ctx 必填
+ * @param exchange 必填
+ * @param chain 非必填
+ * @return /
+ */
+ public static Context setContext(Context ctx, ServerWebExchange exchange, WebFilterChain chain) {
+ return ctx
+ .put(EXCHANGE_KEY, exchange)
+ .put(CHAIN_KEY, chain);
}
-
+
/**
- * 获取上下文对象, 并设置到同步上下文中
- * @return see note
+ * 在流式上下文获取 ServerWebExchange
+ * @param ctx /
+ * @return /
*/
- public static Mono getContextAndSetSync() {
- // 从全局 Mono 获取
- return Mono.deferContextual(Mono::just).map(ctx -> {
- // 设置到sync中
- SaReactorSyncHolder.setContext(ctx.get(CONTEXT_KEY));
- return ctx.get(CONTEXT_KEY);
- }).doFinally(r->{
- // 从sync中清除
- SaReactorSyncHolder.clearContext();
+ public static ServerWebExchange getExchange(ContextView ctx) {
+ return ctx.get(EXCHANGE_KEY);
+ }
+
+ /**
+ * 在流式上下文获取 WebFilterChain
+ * @param ctx /
+ * @return /
+ */
+ public static WebFilterChain getChain(ContextView ctx) {
+ return ctx.get(CHAIN_KEY);
+ }
+
+ /**
+ * 获取 Mono < ServerWebExchange >
+ * @return /
+ */
+ public static Mono getMonoExchange() {
+ return Mono.deferContextual(ctx -> Mono.just(getExchange(ctx)));
+ }
+
+ /**
+ * 将 exchange 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
+ *
+ * @return /
+ */
+ public static Mono sync(SaRetGenericFunction fun) {
+ return Mono.deferContextual(ctx -> {
+ try {
+ SaReactorSyncHolder.setContext(ctx.get(EXCHANGE_KEY));
+ return Mono.just(fun.run());
+ } finally {
+ SaReactorSyncHolder.clearContext();
+ }
});
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java
index 684a9253..c100ade8 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/context/SaReactorSyncHolder.java
@@ -15,29 +15,28 @@
*/
package cn.dev33.satoken.reactor.context;
-import org.springframework.web.server.ServerWebExchange;
-
import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage;
import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage.Box;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
-import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.fun.SaRetGenericFunction;
import cn.dev33.satoken.reactor.model.SaRequestForReactor;
import cn.dev33.satoken.reactor.model.SaResponseForReactor;
import cn.dev33.satoken.reactor.model.SaStorageForReactor;
+import org.springframework.web.server.ServerWebExchange;
/**
* Reactor上下文操作(同步),持有当前请求的 ServerWebExchange 全局引用
*
* @author click33
- * @since 1.34.0
+ * @since 1.19.0
*/
public class SaReactorSyncHolder {
-
+
/**
- * 写入上下文对象
- * @param exchange see note
+ * 在同步上下文写入 ServerWebExchange
+ * @param exchange /
*/
public static void setContext(ServerWebExchange exchange) {
SaRequest request = new SaRequestForReactor(exchange.getRequest());
@@ -45,35 +44,35 @@ public class SaReactorSyncHolder {
SaStorage storage = new SaStorageForReactor(exchange);
SaTokenContextForThreadLocalStorage.setBox(request, response, storage);
}
-
+
/**
- * 获取上下文对象
- * @return see note
- */
- public static ServerWebExchange getContext() {
- Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
- return (ServerWebExchange)box.getStorage().getSource();
- }
-
- /**
- * 清除上下文对象
+ * 在同步上下文清除 ServerWebExchange
*/
public static void clearContext() {
SaTokenContextForThreadLocalStorage.clearBox();
}
-
+
/**
- * 写入上下文对象, 并在执行函数后将其清除
- * @param exchange see note
- * @param fun see note
+ * 在同步上下文获取 ServerWebExchange
+ * @return /
*/
- public static void setContext(ServerWebExchange exchange, SaFunction fun) {
+ public static ServerWebExchange getExchange() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (ServerWebExchange)box.getStorage().getSource();
+ }
+
+ /**
+ * 将 exchange 写入到同步上下文中,并执行一段代码,执行完毕清除上下文
+ * @param exchange /
+ * @param fun /
+ */
+ public static R setContext(ServerWebExchange exchange, SaRetGenericFunction fun) {
try {
setContext(exchange);
- fun.run();
+ return fun.run();
} finally {
clearContext();
}
}
-
+
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java
index cef0a73b..da6d6859 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaFirewallCheckFilterForReactor.java
@@ -15,10 +15,13 @@
*/
package cn.dev33.satoken.reactor.filter;
+import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.FirewallCheckException;
import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.model.SaRequestForReactor;
import cn.dev33.satoken.reactor.model.SaResponseForReactor;
+import cn.dev33.satoken.reactor.util.SaReactorOperateUtil;
import cn.dev33.satoken.strategy.SaFirewallStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
@@ -43,25 +46,29 @@ public class SaFirewallCheckFilterForReactor implements WebFilter {
SaResponseForReactor saResponse = new SaResponseForReactor(exchange.getResponse());
try {
+ SaReactorSyncHolder.setContext(exchange);
SaFirewallStrategy.instance.check.execute(saRequest, saResponse, exchange);
}
- catch (StopMatchException e) {
- // 如果是 StopMatchException 异常,代表通过了防火墙验证,进入 Controller
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
}
+ // FirewallCheckException 异常则交由异常处理策略处理
catch (FirewallCheckException e) {
- // FirewallCheckException 异常则交由异常处理策略处理
if(SaFirewallStrategy.instance.checkFailHandle == null) {
- exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
- return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(e.getMessage().getBytes())));
+ return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
} else {
SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
return Mono.empty();
}
}
+ finally {
+ SaReactorSyncHolder.clearContext();
+ }
// 更多异常则不处理,交由 Web 框架处理
// 向下执行
return chain.filter(exchange);
}
-}
+}
\ No newline at end of file
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java
index 276f8fa2..83c59151 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaReactorFilter.java
@@ -21,9 +21,8 @@ import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
-import cn.dev33.satoken.reactor.context.SaReactorHolder;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
-import cn.dev33.satoken.reactor.error.SaReactorSpringBootErrorCode;
+import cn.dev33.satoken.reactor.util.SaReactorOperateUtil;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
@@ -96,7 +95,7 @@ public class SaReactorFilter implements SaFilter, WebFilter {
* 异常处理函数:每次[认证函数]发生异常时执行此函数
*/
public SaFilterErrorStrategy error = e -> {
- throw new SaTokenException(e).setCode(SaReactorSpringBootErrorCode.CODE_20205);
+ throw new SaTokenException(e);
};
/**
@@ -123,60 +122,28 @@ public class SaReactorFilter implements SaFilter, WebFilter {
return this;
}
-
// ------------------------ filter
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
-
- // 写入WebFilterChain对象
- exchange.getAttributes().put(SaReactorHolder.CHAIN_KEY, chain);
-
- // ---------- 全局认证处理
- try {
- // 写入全局上下文 (同步)
- SaReactorSyncHolder.setContext(exchange);
-
- // 执行全局过滤器
- beforeAuth.run(null);
- SaRouter.match(includeList).notMatch(excludeList).check(r -> {
- auth.run(null);
- });
-
- } catch (StopMatchException e) {
- // StopMatchException 异常代表:停止匹配,进入Controller
- } catch (Throwable e) {
- // 1. 获取异常处理策略结果
- String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
-
- // 2. 写入输出流
- // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
- // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
- if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
- exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
- }
- return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
-
- } finally {
- // 清除上下文
+ // ---------- 全局认证处理
+ try {
+ SaReactorSyncHolder.setContext(exchange);
+ beforeAuth.run(null);
+ SaRouter.match(includeList).notMatch(excludeList).check(r -> auth.run(null));
+ }
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ return SaReactorOperateUtil.writeResult(exchange, e.getMessage());
+ }
+ catch (Throwable e) {
+ return SaReactorOperateUtil.writeResult(exchange, String.valueOf(error.run(e)));
+ }
+ finally {
SaReactorSyncHolder.clearContext();
}
- // ---------- 执行
-
- // 写入全局上下文 (同步)
- SaReactorSyncHolder.setContext(exchange);
-
- // 执行
- return chain.filter(exchange).contextWrite(ctx -> {
- // 写入全局上下文 (异步)
- ctx = ctx.put(SaReactorHolder.CONTEXT_KEY, exchange);
- return ctx;
- }).doFinally(r -> {
- // 清除上下文
- SaReactorSyncHolder.clearContext();
- });
+ return chain.filter(exchange);
}
-
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java
new file mode 100644
index 00000000..27936837
--- /dev/null
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaTokenContextFilterForReactor.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.reactor.filter;
+
+import cn.dev33.satoken.reactor.context.SaReactorHolder;
+import cn.dev33.satoken.util.SaTokenConsts;
+import org.springframework.core.annotation.Order;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+/**
+ * SaTokenContext 上下文初始化过滤器 (基于 Reactor)
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+@Order(SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
+public class SaTokenContextFilterForReactor implements WebFilter {
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+ return chain.filter(exchange)
+ .contextWrite(ctx -> SaReactorHolder.setContext(ctx, exchange, chain))
+ .doFinally(r -> {
+ // 在流式上下文中保存的数据会随着流式操作的结束而销毁,所以此处无需手动清除数据
+ });
+ }
+
+}
\ No newline at end of file
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 41131b6f..ce2e4275 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
@@ -184,7 +184,7 @@ public class SaRequestForReactor implements SaRequest {
*/
@Override
public Object forward(String path) {
- ServerWebExchange exchange = SaReactorSyncHolder.getContext();
+ ServerWebExchange exchange = SaReactorSyncHolder.getExchange();
WebFilterChain chain = exchange.getAttribute(SaReactorHolder.CHAIN_KEY);
ServerHttpRequest newRequest = request.mutate().path(path).build();
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java
index c02dfbac..1b4e785a 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextForSpringReactor.java
@@ -16,22 +16,15 @@
package cn.dev33.satoken.reactor.spring;
import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
-import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
/**
+ * 此为低版本(<1.42.0) 的上下文处理方案,仅做留档,如无必要请勿使用
+ *
* Sa-Token 上下文处理器 [ Spring Reactor 版本实现 ] ,基于 SaTokenContextForThreadLocal 定制
- *
+ *
* @author click33
- * @since 1.34.0
+ * @since 1.33.0
*/
public class SaTokenContextForSpringReactor extends SaTokenContextForThreadLocal {
-
- /**
- * 重写路由匹配方法
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return SaPathPatternParserUtil.match(pattern, path);
- }
-
+
}
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java
index 04fe1d02..d5561274 100644
--- a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenContextRegister.java
@@ -15,8 +15,10 @@
*/
package cn.dev33.satoken.reactor.spring;
-import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.reactor.filter.SaFirewallCheckFilterForReactor;
+import cn.dev33.satoken.reactor.filter.SaTokenContextFilterForReactor;
+import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
+import cn.dev33.satoken.strategy.SaStrategy;
import org.springframework.context.annotation.Bean;
/**
@@ -27,18 +29,25 @@ import org.springframework.context.annotation.Bean;
*/
public class SaTokenContextRegister {
+ public SaTokenContextRegister() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return SaPathPatternParserUtil.match(pattern, path);
+ };
+ }
+
/**
- * 获取上下文处理器组件 (Spring Reactor 版)
+ * 上下文过滤器
*
* @return /
*/
@Bean
- public SaTokenContext getSaTokenContextForSpringReactor() {
- return new SaTokenContextForSpringReactor();
+ public SaTokenContextFilterForReactor saTokenContextFilterForServlet() {
+ return new SaTokenContextFilterForReactor();
}
/**
- * 请求 path 校验过滤器
+ * 防火墙过滤器
*
* @return /
*/
diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java
new file mode 100644
index 00000000..706501bf
--- /dev/null
+++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/util/SaReactorOperateUtil.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.reactor.util;
+
+import cn.dev33.satoken.util.SaTokenConsts;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * Reactor 操作工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaReactorOperateUtil {
+
+ /**
+ * 写入结果到输出流
+ * @param exchange /
+ * @param result /
+ * @return /
+ */
+ public static Mono writeResult(ServerWebExchange exchange, String result) {
+ // 写入输出流
+ // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
+ // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
+ if(exchange.getResponse().getHeaders().getFirst(SaTokenConsts.CONTENT_TYPE_KEY) == null) {
+ exchange.getResponse().getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
+ }
+ return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(result.getBytes())));
+ }
+
+}
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 4b25c49b..131668ea 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
@@ -187,7 +187,7 @@ public class SaRequestForServlet implements SaRequest {
@Override
public Object forward(String path) {
try {
- HttpServletResponse response = (HttpServletResponse)SaManager.getSaTokenContextOrSecond().getResponse().getSource();
+ HttpServletResponse response = (HttpServletResponse)SaManager.getSaTokenContext().getResponse().getSource();
request.getRequestDispatcher(path).forward(request, response);
return null;
} catch (ServletException | IOException e) {
diff --git a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaServletOperateUtil.java b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaServletOperateUtil.java
new file mode 100644
index 00000000..0390e357
--- /dev/null
+++ b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaServletOperateUtil.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.servlet.util;
+
+import cn.dev33.satoken.util.SaTokenConsts;
+
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
+/**
+ * Servlet 操作工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaServletOperateUtil {
+
+ /**
+ * 写入结果到输出流
+ * @param response /
+ * @param result /
+ */
+ public static void writeResult(ServletResponse response, String result) throws IOException {
+ // 写入输出流
+ // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
+ // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
+ if(response.getContentType() == null) {
+ response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
+ }
+ response.getWriter().print(result);
+ response.getWriter().flush();
+ }
+
+
+}
diff --git a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java
new file mode 100644
index 00000000..48bfcf59
--- /dev/null
+++ b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/util/SaTokenContextUtil.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.servlet.util;
+
+import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage;
+import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage.Box;
+import cn.dev33.satoken.context.model.SaRequest;
+import cn.dev33.satoken.context.model.SaResponse;
+import cn.dev33.satoken.context.model.SaStorage;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.servlet.model.SaRequestForServlet;
+import cn.dev33.satoken.servlet.model.SaResponseForServlet;
+import cn.dev33.satoken.servlet.model.SaStorageForServlet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * SaTokenContext 上下文读写工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaTokenContextUtil {
+
+ /**
+ * 写入当前上下文
+ * @param request /
+ * @param response /
+ */
+ public static void setContext(HttpServletRequest request, HttpServletResponse response) {
+ SaRequest req = new SaRequestForServlet(request);
+ SaResponse res = new SaResponseForServlet(response);
+ SaStorage stg = new SaStorageForServlet(request);
+ SaTokenContextForThreadLocalStorage.setBox(req, res, stg);
+ }
+
+ /**
+ * 清除当前上下文
+ */
+ public static void clearContext() {
+ SaTokenContextForThreadLocalStorage.clearBox();
+ }
+
+ /**
+ * 写入上下文对象, 并在执行函数后将其清除
+ * @param request /
+ * @param response /
+ * @param fun /
+ */
+ public static void setContext(HttpServletRequest request, HttpServletResponse response, SaFunction fun) {
+ try {
+ setContext(request, response);
+ fun.run();
+ } finally {
+ clearContext();
+ }
+ }
+
+ /**
+ * 获取当前 Box
+ * @return /
+ */
+ public static Box getBox() {
+ return SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ }
+
+ /**
+ * 获取当前 Request
+ * @return /
+ */
+ public static HttpServletRequest getRequest() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (HttpServletRequest) box.getRequest().getSource();
+ }
+
+ /**
+ * 获取当前 Response
+ * @return /
+ */
+ public static HttpServletResponse getResponse() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (HttpServletResponse) box.getResponse().getSource();
+ }
+
+}
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java
index 206dcdcd..0738e9e7 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaBeanRegister.java
@@ -17,11 +17,14 @@ package cn.dev33.satoken.solon;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.solon.integration.SaFirewallCheckFilterForSolon;
+import cn.dev33.satoken.solon.integration.SaTokenContextFilterForSolon;
+import cn.dev33.satoken.strategy.SaStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.handle.Filter;
+import org.noear.solon.core.util.PathAnalyzer;
/**
* 注册Sa-Token所需要的Bean
@@ -32,6 +35,13 @@ import org.noear.solon.core.handle.Filter;
@Configuration
public class SaBeanRegister {
+ public SaBeanRegister() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return PathAnalyzer.get(pattern).matches(path);
+ };
+ }
+
/**
* 获取配置Bean
*
@@ -47,7 +57,17 @@ public class SaBeanRegister {
}
/**
- * 防火墙校验过滤器
+ * 上下文过滤器
+ *
+ * @return /
+ */
+ @Bean(index = SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
+ public Filter saTokenContextFilterForSolon() {
+ return new SaTokenContextFilterForSolon();
+ }
+
+ /**
+ * 防火墙过滤器
*
* @return /
*/
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaSolonPlugin.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaSolonPlugin.java
index ea8e9bbb..c0324868 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaSolonPlugin.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/SaSolonPlugin.java
@@ -17,7 +17,6 @@ package cn.dev33.satoken.solon;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.solon.json.SaJsonTemplateForSnack3;
-import cn.dev33.satoken.solon.model.SaContextForSolon;
import cn.dev33.satoken.solon.oauth2.SaOAuth2BeanInject;
import cn.dev33.satoken.solon.oauth2.SaOAuth2BeanRegister;
import cn.dev33.satoken.solon.sso.SaSsoBeanInject;
@@ -33,8 +32,6 @@ public class SaSolonPlugin implements Plugin {
@Override
public void start(AppContext context) {
- // 注入上下文Bean
- SaManager.setSaTokenContext(new SaContextForSolon());
// 注入JSON解析器Bean
SaManager.setSaJsonTemplate(new SaJsonTemplateForSnack3());
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaFirewallCheckFilterForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaFirewallCheckFilterForSolon.java
index caf225d3..4bd14cc7 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaFirewallCheckFilterForSolon.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaFirewallCheckFilterForSolon.java
@@ -15,10 +15,12 @@
*/
package cn.dev33.satoken.solon.integration;
+import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.FirewallCheckException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.solon.model.SaRequestForSolon;
import cn.dev33.satoken.solon.model.SaResponseForSolon;
+import cn.dev33.satoken.solon.util.SaSolonOperateUtil;
import cn.dev33.satoken.strategy.SaFirewallStrategy;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.Filter;
@@ -41,17 +43,17 @@ public class SaFirewallCheckFilterForSolon implements Filter {
try {
SaFirewallStrategy.instance.check.execute(saRequest, saResponse, null);
}
- catch (StopMatchException e) {
- // 如果是 StopMatchException 异常,代表通过了防火墙验证,进入 Controller
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaSolonOperateUtil.writeResult(ctx, e.getMessage());
+ return;
}
catch (FirewallCheckException e) {
- // FirewallCheckException 异常则交由异常处理策略处理
if(SaFirewallStrategy.instance.checkFailHandle == null) {
- ctx.render(e.getMessage());
+ SaSolonOperateUtil.writeResult(ctx, e.getMessage());
} else {
SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
}
- ctx.setHandled(true);
return;
}
// 更多异常则不处理,交由 Web 框架处理
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenContextFilterForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenContextFilterForSolon.java
new file mode 100644
index 00000000..75e80b97
--- /dev/null
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenContextFilterForSolon.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.solon.integration;
+
+import cn.dev33.satoken.solon.util.SaTokenContextUtil;
+import org.noear.solon.core.handle.Context;
+import org.noear.solon.core.handle.Filter;
+import org.noear.solon.core.handle.FilterChain;
+
+/**
+ * 上下文初始化过滤器 (基于 Solon)
+ *
+ * @author noear
+ * @since 1.42.0
+ */
+public class SaTokenContextFilterForSolon implements Filter {
+
+ @Override
+ public void doFilter(Context ctx, FilterChain chain) throws Throwable {
+ try {
+ SaTokenContextUtil.setContext(ctx);
+ chain.doFilter(ctx);
+ } finally {
+ SaTokenContextUtil.clearContext();
+ }
+ }
+
+}
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 0ebfecda..4d1324ee 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
@@ -18,10 +18,11 @@ package cn.dev33.satoken.solon.integration;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.StopMatchException;
+import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
-import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.solon.util.SaSolonOperateUtil;
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
import org.noear.solon.Solon;
import org.noear.solon.core.handle.*;
@@ -180,22 +181,14 @@ public class SaTokenFilter implements SaFilter, Filter { //之所以改名,为
auth.run(finalMainHandler);
}
});
- } catch (StopMatchException e) {
- // StopMatchException 异常代表:停止匹配,进入Controller
- } catch (SaTokenException e) {
- // 1. 获取异常处理策略结果
- Object result;
- if (e instanceof BackResultException) {
- result = e.getMessage();
- } else {
- result = error.run(e);
- }
-
- // 2. 写入输出流
- if (result != null) {
- ctx.render(result);
- }
- ctx.setHandled(true);
+ }
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaSolonOperateUtil.writeResult(ctx, e.getMessage());
+ return;
+ }
+ catch (SaTokenException e) {
+ SaSolonOperateUtil.writeResult(ctx, error.run(e));
return;
}
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 62460cd7..78ba6569 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
@@ -22,6 +22,7 @@ import cn.dev33.satoken.filter.SaFilter;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.solon.util.SaSolonOperateUtil;
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
import org.noear.solon.core.handle.*;
import org.noear.solon.core.route.RouterInterceptor;
@@ -211,22 +212,14 @@ public class SaTokenInterceptor implements SaFilter, RouterInterceptor {
}
});
- } catch (StopMatchException e) {
- // StopMatchException 异常代表:停止匹配,进入Controller
- } catch (SaTokenException e) {
- // 1. 获取异常处理策略结果
- Object result;
- if (e instanceof BackResultException) {
- result = e.getMessage();
- } else {
- result = error.run(e);
- }
-
- // 2. 写入输出流
- if (result != null) {
- ctx.render(result);
- }
- ctx.setHandled(true);
+ }
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaSolonOperateUtil.writeResult(ctx, e.getMessage());
+ return;
+ }
+ catch (SaTokenException e) {
+ SaSolonOperateUtil.writeResult(ctx, error.run(e));
return;
}
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java
index 2194eea8..0c406035 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaContextForSolon.java
@@ -20,13 +20,15 @@ import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import org.noear.solon.core.handle.Context;
-import org.noear.solon.core.util.PathAnalyzer;
/**
+ * 此为低版本(<1.42.0) 的上下文处理方案,基于 Solon 内部封装 Context.current() 读写上下文,仅做留档,如无必要请勿使用
+ *
* @author noear
* @since 1.4
*/
public class SaContextForSolon implements SaTokenContext {
+
/**
* 获取当前请求的Request对象
*/
@@ -51,14 +53,6 @@ public class SaContextForSolon implements SaTokenContext {
return new SaStorageForSolon();
}
- /**
- * 校验指定路由匹配符是否可以匹配成功指定路径
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return PathAnalyzer.get(pattern).matches(path);
- }
-
/**
* 此上下文是否有效
* @return /
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 cc6d2ef1..ae0af44b 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
@@ -32,7 +32,11 @@ public class SaRequestForSolon implements SaRequest {
protected Context ctx;
public SaRequestForSolon() {
- ctx = Context.current();
+ this(Context.current());
+ }
+
+ public SaRequestForSolon(Context ctx) {
+ this.ctx = ctx;
}
@Override
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaResponseForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaResponseForSolon.java
index a591b1d3..dfb3748f 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaResponseForSolon.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaResponseForSolon.java
@@ -27,7 +27,11 @@ public class SaResponseForSolon implements SaResponse {
protected Context ctx;
public SaResponseForSolon() {
- ctx = Context.current();
+ this(Context.current());
+ }
+
+ public SaResponseForSolon(Context ctx) {
+ this.ctx = ctx;
}
@Override
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java
index 90fa90a2..08368723 100644
--- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaStorageForSolon.java
@@ -27,7 +27,11 @@ public class SaStorageForSolon implements SaStorage {
protected Context ctx;
public SaStorageForSolon() {
- ctx = Context.current();
+ this(Context.current());
+ }
+
+ public SaStorageForSolon(Context ctx) {
+ this.ctx = ctx;
}
@Override
diff --git a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/error/SaSpringBootErrorCode.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaSolonOperateUtil.java
similarity index 54%
rename from sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/error/SaSpringBootErrorCode.java
rename to sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaSolonOperateUtil.java
index dee05007..05463a1c 100644
--- a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/error/SaSpringBootErrorCode.java
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaSolonOperateUtil.java
@@ -13,29 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package cn.dev33.satoken.error;
+package cn.dev33.satoken.solon.util;
+
+import org.noear.solon.core.handle.Context;
/**
- * 定义 sa-token-spring-boot-starter 所有异常细分状态码
- *
+ * Solon 操作工具类
+ *
* @author click33
- * @since 1.34.0
+ * @since 1.42.0
*/
-public interface SaSpringBootErrorCode {
-
- /** 企图在非 Web 上下文获取 Request、Response 等对象 */
- int CODE_20101 = 20101;
+public class SaSolonOperateUtil {
- /** 对象转 JSON 字符串失败 */
- int CODE_20103 = 20103;
+ /**
+ * 写入结果到输出流
+ * @param ctx /
+ * @param result /
+ */
+ public static void writeResult(Context ctx, Object result) throws Throwable {
+ if (result != null) {
+ ctx.render(result);
+ }
+ ctx.setHandled(true);
+ }
- /** JSON 字符串转 Map 失败 */
- int CODE_20104 = 20104;
-
- /** JSON 字符串转 Object 失败 */
- int CODE_20106 = 20106;
-
- /** 默认的 Filter 异常处理函数 */
- int CODE_20105 = 20105;
}
diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaTokenContextUtil.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaTokenContextUtil.java
new file mode 100644
index 00000000..35f11de5
--- /dev/null
+++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/util/SaTokenContextUtil.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.solon.util;
+
+import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage;
+import cn.dev33.satoken.context.SaTokenContextForThreadLocalStorage.Box;
+import cn.dev33.satoken.context.model.SaRequest;
+import cn.dev33.satoken.context.model.SaResponse;
+import cn.dev33.satoken.context.model.SaStorage;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.solon.model.SaRequestForSolon;
+import cn.dev33.satoken.solon.model.SaResponseForSolon;
+import cn.dev33.satoken.solon.model.SaStorageForSolon;
+import org.noear.solon.core.handle.Context;
+
+/**
+ * SaTokenContext 上下文读写工具类
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+public class SaTokenContextUtil {
+
+ /**
+ * 写入当前上下文
+ */
+ public static void setContext(Context ctx) {
+ SaRequest req = new SaRequestForSolon(ctx);
+ SaResponse res = new SaResponseForSolon(ctx);
+ SaStorage stg = new SaStorageForSolon(ctx);
+ SaTokenContextForThreadLocalStorage.setBox(req, res, stg);
+ }
+
+ /**
+ * 清除当前上下文
+ */
+ public static void clearContext() {
+ SaTokenContextForThreadLocalStorage.clearBox();
+ }
+
+ /**
+ * 写入上下文对象, 并在执行函数后将其清除
+ * @param ctx /
+ * @param fun /
+ */
+ public static void setContext(Context ctx, SaFunction fun) {
+ try {
+ setContext(ctx);
+ fun.run();
+ } finally {
+ clearContext();
+ }
+ }
+
+ /**
+ * 获取当前 Box
+ * @return /
+ */
+ public static Box getBox() {
+ return SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ }
+
+ /**
+ * 获取当前 Context
+ * @return /
+ */
+ public static Context getContext() {
+ Box box = SaTokenContextForThreadLocalStorage.getBoxNotNull();
+ return (Context) box.getStorage().getSource();
+ }
+
+}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForServlet.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForServlet.java
index b3abf110..32f67259 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForServlet.java
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForServlet.java
@@ -15,10 +15,12 @@
*/
package cn.dev33.satoken.filter;
+import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.FirewallCheckException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
+import cn.dev33.satoken.servlet.util.SaServletOperateUtil;
import cn.dev33.satoken.strategy.SaFirewallStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
@@ -48,15 +50,14 @@ public class SaFirewallCheckFilterForServlet implements Filter {
try {
SaFirewallStrategy.instance.check.execute(saRequest, saResponse, null);
}
- catch (StopMatchException e) {
- // 如果是 StopMatchException 异常,代表通过了防火墙验证,进入 Controller
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaServletOperateUtil.writeResult(response, e.getMessage());
+ return;
}
catch (FirewallCheckException e) {
- // FirewallCheckException 异常则交由异常处理策略处理
if(SaFirewallStrategy.instance.checkFailHandle == null) {
- response.setContentType("text/plain; charset=utf-8");
- response.getWriter().print(e.getMessage());
- response.getWriter().flush();
+ SaServletOperateUtil.writeResult(response, e.getMessage());
} else {
SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
}
@@ -68,14 +69,4 @@ public class SaFirewallCheckFilterForServlet implements Filter {
chain.doFilter(request, response);
}
- @Override
- public void init(FilterConfig filterConfig) {
- }
-
- @Override
- public void destroy() {
- }
-
-
-
}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java
index 8fd3eb9f..bcb2e6e8 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java
@@ -15,11 +15,11 @@
*/
package cn.dev33.satoken.filter;
-import cn.dev33.satoken.error.SaSpringBootErrorCode;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.servlet.util.SaServletOperateUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import org.springframework.core.annotation.Order;
@@ -30,7 +30,7 @@ import java.util.Arrays;
import java.util.List;
/**
- * Servlet 全局鉴权过滤器
+ * 全局鉴权过滤器 (基于 Servlet)
*
* 默认优先级为 -100,尽量保证在其它过滤器之前执行
*
@@ -89,7 +89,7 @@ public class SaServletFilter implements SaFilter, Filter {
* 异常处理函数:每次[认证函数]发生异常时执行此函数
*/
public SaFilterErrorStrategy error = e -> {
- throw new SaTokenException(e).setCode(SaSpringBootErrorCode.CODE_20105);
+ throw new SaTokenException(e);
};
/**
@@ -128,21 +128,14 @@ public class SaServletFilter implements SaFilter, Filter {
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
auth.run(null);
});
-
- } catch (StopMatchException e) {
- // StopMatchException 异常代表:停止匹配,进入Controller
-
- } catch (Throwable e) {
- // 1. 获取异常处理策略结果
- String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
-
- // 2. 写入输出流
- // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
- // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
- if(response.getContentType() == null) {
- response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
- }
- response.getWriter().print(result);
+ }
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaServletOperateUtil.writeResult(response, e.getMessage());
+ return;
+ }
+ catch (Throwable e) {
+ SaServletOperateUtil.writeResult(response, String.valueOf(error.run(e)));
return;
}
@@ -150,14 +143,4 @@ public class SaServletFilter implements SaFilter, Filter {
chain.doFilter(request, response);
}
- @Override
- public void init(FilterConfig filterConfig) {
- }
-
- @Override
- public void destroy() {
- }
-
-
-
}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForServlet.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForServlet.java
new file mode 100644
index 00000000..73bee39f
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForServlet.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.filter;
+
+import cn.dev33.satoken.servlet.util.SaTokenContextUtil;
+import cn.dev33.satoken.util.SaTokenConsts;
+import org.springframework.core.annotation.Order;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * SaTokenContext 上下文初始化过滤器 (基于 Servlet)
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+@Order(SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
+public class SaTokenContextFilterForServlet implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ try {
+ SaTokenContextUtil.setContext((HttpServletRequest) request, (HttpServletResponse) response);
+ chain.doFilter(request, response);
+ } finally {
+ SaTokenContextUtil.clearContext();
+ }
+ }
+
+}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpring.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpring.java
deleted file mode 100644
index dd826350..00000000
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpring.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2020-2099 sa-token.cc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package cn.dev33.satoken.spring;
-
-import cn.dev33.satoken.context.SaTokenContext;
-import cn.dev33.satoken.context.model.SaRequest;
-import cn.dev33.satoken.context.model.SaResponse;
-import cn.dev33.satoken.context.model.SaStorage;
-import cn.dev33.satoken.servlet.model.SaRequestForServlet;
-import cn.dev33.satoken.servlet.model.SaResponseForServlet;
-import cn.dev33.satoken.servlet.model.SaStorageForServlet;
-import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder;
-
-/**
- * Sa-Token 上下文处理器 [ SpringMVC版本实现 ]。在 SpringMVC、SpringBoot 中使用 Sa-Token 时,必须注入此实现类,否则会出现上下文无效异常
- *
- * @author click33
- * @since 1.19.0
- */
-public class SaTokenContextForSpring implements SaTokenContext {
-
- /**
- * 获取当前请求的 Request 包装对象
- */
- @Override
- public SaRequest getRequest() {
- return new SaRequestForServlet(SpringMVCUtil.getRequest());
- }
-
- /**
- * 获取当前请求的 Response 包装对象
- */
- @Override
- public SaResponse getResponse() {
- return new SaResponseForServlet(SpringMVCUtil.getResponse());
- }
-
- /**
- * 获取当前请求的 Storage 包装对象
- */
- @Override
- public SaStorage getStorage() {
- return new SaStorageForServlet(SpringMVCUtil.getRequest());
- }
-
- /**
- * 判断:指定路由匹配符是否可以匹配成功指定路径
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return SaPatternsRequestConditionHolder.match(pattern, path);
- }
-
- /**
- * 判断:在本次请求中,此上下文是否可用。
- */
- @Override
- public boolean isValid() {
- return SpringMVCUtil.isWeb();
- }
-
-}
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java
index e8851475..4f53b570 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java
@@ -15,8 +15,10 @@
*/
package cn.dev33.satoken.spring;
-import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.filter.SaFirewallCheckFilterForServlet;
+import cn.dev33.satoken.filter.SaTokenContextFilterForServlet;
+import cn.dev33.satoken.spring.pathmatch.SaPatternsRequestConditionHolder;
+import cn.dev33.satoken.strategy.SaStrategy;
import org.springframework.context.annotation.Bean;
/**
@@ -27,18 +29,25 @@ import org.springframework.context.annotation.Bean;
*/
public class SaTokenContextRegister {
- /**
- * 获取上下文处理器组件 (Spring版)
- *
- * @return /
- */
- @Bean
- public SaTokenContext getSaTokenContextForSpring() {
- return new SaTokenContextForSpring();
+ public SaTokenContextRegister() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return SaPatternsRequestConditionHolder.match(pattern, path);
+ };
}
/**
- * 请求 path 校验过滤器
+ * 上下文过滤器
+ *
+ * @return /
+ */
+ @Bean
+ public SaTokenContextFilterForServlet saTokenContextFilterForServlet() {
+ return new SaTokenContextFilterForServlet();
+ }
+
+ /**
+ * 防火墙过滤器
*
* @return /
*/
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringBootVersionCompatibilityChecker.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringBootVersionCompatibilityChecker.java
index 755c274c..721fddfe 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringBootVersionCompatibilityChecker.java
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringBootVersionCompatibilityChecker.java
@@ -5,7 +5,7 @@ import cn.dev33.satoken.util.SaFoxUtil;
import org.springframework.boot.SpringBootVersion;
/**
- * SpringBoot 版本与 Sa-Token 版本兼容检查器
+ * SpringBoot 版本与 Sa-Token 版本兼容检查器,当开发者错误的在 SpringBoot3.x 项目中引入当前集成包时,将在控制台做出提醒并阻断项目启动
*
* @author Uncarbon
* @since 1.38.0
diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java
index 16514c5d..75cad04c 100644
--- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java
+++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java
@@ -15,14 +15,12 @@
*/
package cn.dev33.satoken.spring;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import cn.dev33.satoken.exception.NotWebContextException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
-import cn.dev33.satoken.error.SaSpringBootErrorCode;
-import cn.dev33.satoken.exception.NotWebContextException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
/**
* SpringMVC 相关操作工具类,快速获取当前会话的 HttpServletRequest、HttpServletResponse 对象
@@ -42,7 +40,7 @@ public class SpringMVCUtil {
public static HttpServletRequest getRequest() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(servletRequestAttributes == null) {
- throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest").setCode(SaSpringBootErrorCode.CODE_20101);
+ throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest");
}
return servletRequestAttributes.getRequest();
}
@@ -54,7 +52,7 @@ public class SpringMVCUtil {
public static HttpServletResponse getResponse() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(servletRequestAttributes == null) {
- throw new NotWebContextException("非 web 上下文无法获取 HttpServletResponse").setCode(SaSpringBootErrorCode.CODE_20101);
+ throw new NotWebContextException("非 web 上下文无法获取 HttpServletResponse");
}
return servletRequestAttributes.getResponse();
}
diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java
index cb162ba0..b279eef1 100644
--- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java
+++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java
@@ -15,10 +15,12 @@
*/
package cn.dev33.satoken.filter;
+import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.FirewallCheckException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
+import cn.dev33.satoken.servlet.util.SaJakartaServletOperateUtil;
import cn.dev33.satoken.strategy.SaFirewallStrategy;
import cn.dev33.satoken.util.SaTokenConsts;
import jakarta.servlet.*;
@@ -48,15 +50,14 @@ public class SaFirewallCheckFilterForJakartaServlet implements Filter {
try {
SaFirewallStrategy.instance.check.execute(saRequest, saResponse, null);
}
- catch (StopMatchException e) {
- // 如果是 StopMatchException 异常,代表通过了防火墙验证,进入 Controller
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaJakartaServletOperateUtil.writeResult(response, e.getMessage());
+ return;
}
catch (FirewallCheckException e) {
- // FirewallCheckException 异常则交由异常处理策略处理
if(SaFirewallStrategy.instance.checkFailHandle == null) {
- response.setContentType("text/plain; charset=utf-8");
- response.getWriter().print(e.getMessage());
- response.getWriter().flush();
+ SaJakartaServletOperateUtil.writeResult(response, e.getMessage());
} else {
SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null);
}
@@ -68,14 +69,5 @@ public class SaFirewallCheckFilterForJakartaServlet implements Filter {
chain.doFilter(request, response);
}
- @Override
- public void init(FilterConfig filterConfig) {
- }
-
- @Override
- public void destroy() {
- }
-
-
}
diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java
index b7dfb153..7d3e6ff9 100644
--- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java
+++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java
@@ -15,11 +15,11 @@
*/
package cn.dev33.satoken.filter;
-import cn.dev33.satoken.error.SaSpringBootErrorCode;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.servlet.util.SaJakartaServletOperateUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import jakarta.servlet.*;
import org.springframework.core.annotation.Order;
@@ -30,7 +30,7 @@ import java.util.Arrays;
import java.util.List;
/**
- * Jakarta-Servlet 全局鉴权过滤器
+ * 全局鉴权过滤器 (基于 Jakarta-Servlet)
*
* 默认优先级为 -100,尽量保证在其它过滤器之前执行
*
@@ -89,7 +89,7 @@ public class SaServletFilter implements SaFilter, Filter {
* 异常处理函数:每次[认证函数]发生异常时执行此函数
*/
public SaFilterErrorStrategy error = e -> {
- throw new SaTokenException(e).setCode(SaSpringBootErrorCode.CODE_20105);
+ throw new SaTokenException(e);
};
/**
@@ -128,36 +128,19 @@ public class SaServletFilter implements SaFilter, Filter {
SaRouter.match(includeList).notMatch(excludeList).check(r -> {
auth.run(null);
});
-
- } catch (StopMatchException e) {
- // StopMatchException 异常代表:停止匹配,进入Controller
-
- } catch (Throwable e) {
- // 1. 获取异常处理策略结果
- String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));
-
- // 2. 写入输出流
- // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 return 前自行设置 Content-Type 为 application/json
- // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
- if(response.getContentType() == null) {
- response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN);
- }
- response.getWriter().print(result);
+ }
+ catch (StopMatchException ignored) {}
+ catch (BackResultException e) {
+ SaJakartaServletOperateUtil.writeResult(response, e.getMessage());
+ return;
+ }
+ catch (Throwable e) {
+ SaJakartaServletOperateUtil.writeResult(response, String.valueOf(error.run(e)));
return;
}
// 执行
chain.doFilter(request, response);
}
-
- @Override
- public void init(FilterConfig filterConfig) {
- }
-
- @Override
- public void destroy() {
- }
-
-
}
diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.java
new file mode 100644
index 00000000..cd2ad401
--- /dev/null
+++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020-2099 sa-token.cc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cn.dev33.satoken.filter;
+
+import cn.dev33.satoken.servlet.util.SaTokenContextUtil;
+import cn.dev33.satoken.util.SaTokenConsts;
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.core.annotation.Order;
+
+import java.io.IOException;
+
+/**
+ * SaTokenContext 上下文初始化过滤器 (基于 Jakarta-Servlet)
+ *
+ * @author click33
+ * @since 1.42.0
+ */
+@Order(SaTokenConsts.SA_TOKEN_CONTEXT_FILTER_ORDER)
+public class SaTokenContextFilterForJakartaServlet implements Filter {
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ try {
+ SaTokenContextUtil.setContext((HttpServletRequest) request, (HttpServletResponse) response);
+ chain.doFilter(request, response);
+ } finally {
+ SaTokenContextUtil.clearContext();
+ }
+ }
+
+}
diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java
index 22a9a169..72a34f28 100644
--- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java
+++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java
@@ -22,9 +22,10 @@ import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.servlet.model.SaRequestForServlet;
import cn.dev33.satoken.servlet.model.SaResponseForServlet;
import cn.dev33.satoken.servlet.model.SaStorageForServlet;
-import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
/**
+ * 此为低版本(<1.42.0) 的上下文处理方案,基于 Spring 内部工具类 RequestContextHolder 读写上下文,仅做留档,如无必要请勿使用
+ *
* Sa-Token 上下文处理器 [ SpringBoot3 Jakarta Servlet 版 ],在 SpringBoot3 中使用 Sa-Token 时,必须注入此实现类,否则会出现上下文无效异常
*
* @author click33
@@ -55,14 +56,6 @@ public class SaTokenContextForSpringInJakartaServlet implements SaTokenContext {
public SaStorage getStorage() {
return new SaStorageForServlet(SpringMVCUtil.getRequest());
}
-
- /**
- * 判断:指定路由匹配符是否可以匹配成功指定路径
- */
- @Override
- public boolean matchPath(String pattern, String path) {
- return SaPathPatternParserUtil.match(pattern, path);
- }
/**
* 判断:在本次请求中,此上下文是否可用。
diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java
index 296d3154..48cc43d9 100644
--- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java
+++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java
@@ -15,8 +15,10 @@
*/
package cn.dev33.satoken.spring;
-import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.filter.SaFirewallCheckFilterForJakartaServlet;
+import cn.dev33.satoken.filter.SaTokenContextFilterForJakartaServlet;
+import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil;
+import cn.dev33.satoken.strategy.SaStrategy;
import org.springframework.context.annotation.Bean;
/**
@@ -27,18 +29,25 @@ import org.springframework.context.annotation.Bean;
*/
public class SaTokenContextRegister {
- /**
- * 获取上下文处理器组件 (SpringBoot3 Jakarta Servlet 版)
- *
- * @return /
- */
- @Bean
- public SaTokenContext getSaTokenContextForSpringInJakartaServlet() {
- return new SaTokenContextForSpringInJakartaServlet();
+ public SaTokenContextRegister() {
+ // 重写路由匹配算法
+ SaStrategy.instance.routeMatcher = (pattern, path) -> {
+ return SaPathPatternParserUtil.match(pattern, path);
+ };
}
/**
- * 请求 path 校验过滤器
+ * 上下文过滤器
+ *
+ * @return /
+ */
+ @Bean
+ public SaTokenContextFilterForJakartaServlet saTokenContextFilterForServlet() {
+ return new SaTokenContextFilterForJakartaServlet();
+ }
+
+ /**
+ * 防火墙过滤器
*
* @return /
*/
diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java
index 5eacab05..4f52cdca 100644
--- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java
+++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java
@@ -15,13 +15,11 @@
*/
package cn.dev33.satoken.spring;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-import cn.dev33.satoken.error.SaSpringBootErrorCode;
import cn.dev33.satoken.exception.NotWebContextException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
/**
* SpringMVC 相关操作工具类,快速获取当前会话的 HttpServletRequest、HttpServletResponse 对象
@@ -41,7 +39,7 @@ public class SpringMVCUtil {
public static HttpServletRequest getRequest() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(servletRequestAttributes == null) {
- throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest").setCode(SaSpringBootErrorCode.CODE_20101);
+ throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest");
}
return servletRequestAttributes.getRequest();
}
@@ -53,7 +51,7 @@ public class SpringMVCUtil {
public static HttpServletResponse getResponse() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(servletRequestAttributes == null) {
- throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest").setCode(SaSpringBootErrorCode.CODE_20101);
+ throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest");
}
return servletRequestAttributes.getResponse();
}