From 2d671dc783bb9c3c72b6f5bbd9bf24f6186ccbcb Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Thu, 26 Feb 2026 01:19:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20sa-token-spring-bo?= =?UTF-8?q?ot4-starter=20=E9=9B=86=E6=88=90=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mvn clean.bat | 1 + sa-token-bom/pom.xml | 5 + sa-token-dependencies/pom.xml | 10 +- sa-token-starter/pom.xml | 1 + .../sa-token-spring-boot4-starter/pom.xml | 101 ++++++++++++ ...aFirewallCheckFilterForJakartaServlet.java | 73 +++++++++ .../dev33/satoken/filter/SaServletFilter.java | 146 ++++++++++++++++++ ...SaTokenContextFilterForJakartaServlet.java | 46 ++++++ .../SaTokenCorsFilterForJakartaServlet.java | 55 +++++++ .../satoken/interceptor/SaInterceptor.java | 122 +++++++++++++++ .../java/cn/dev33/satoken/package-info.java | 19 +++ ...TokenContextForSpringInJakartaServlet.java | 68 ++++++++ .../spring/SaTokenContextRegister.java | 70 +++++++++ .../dev33/satoken/spring/SpringMVCUtil.java | 67 ++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + 15 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/pom.xml create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/package-info.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java create mode 100644 sa-token-starter/sa-token-spring-boot4-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/mvn clean.bat b/mvn clean.bat index fd2b3aa4..06d96c24 100644 --- a/mvn clean.bat +++ b/mvn clean.bat @@ -24,6 +24,7 @@ cd sa-token-demo-solon & call mvn clean & cd .. cd sa-token-demo-solon-redisson & call mvn clean & cd .. cd sa-token-demo-springboot & call mvn clean & cd .. cd sa-token-demo-springboot3-redis & call mvn clean & cd .. +cd sa-token-demo-springboot4-redis & call mvn clean & cd .. cd sa-token-demo-springboot-low-version & call mvn clean & cd .. cd sa-token-demo-springboot-redis & call mvn clean & cd .. cd sa-token-demo-springboot-redisson & call mvn clean & cd .. diff --git a/sa-token-bom/pom.xml b/sa-token-bom/pom.xml index 5a7662a9..0a2b0df0 100644 --- a/sa-token-bom/pom.xml +++ b/sa-token-bom/pom.xml @@ -81,6 +81,11 @@ sa-token-spring-boot3-starter ${revision} + + cn.dev33 + sa-token-spring-boot4-starter + ${revision} + diff --git a/sa-token-dependencies/pom.xml b/sa-token-dependencies/pom.xml index 61435bd0..b7f07f5f 100644 --- a/sa-token-dependencies/pom.xml +++ b/sa-token-dependencies/pom.xml @@ -17,11 +17,12 @@ 2.7.18 3.4.3 + 4.0.3 5.3.39 3.7.4 2.13.4.1 2.11.2 - 3.0.0 + 3.1.0 3.1.0 6.0.0 3.0.9.RELEASE @@ -70,6 +71,13 @@ spring-boot-starter-web ${springboot.version} + + + + org.springframework.boot + spring-boot-starter-webmvc + ${springboot4.version} + diff --git a/sa-token-starter/pom.xml b/sa-token-starter/pom.xml index 6456d0a0..ca4312d5 100644 --- a/sa-token-starter/pom.xml +++ b/sa-token-starter/pom.xml @@ -23,6 +23,7 @@ sa-token-spring-boot-autoconfig sa-token-spring-boot-starter sa-token-spring-boot3-starter + sa-token-spring-boot4-starter sa-token-reactor-spring-boot-starter sa-token-reactor-spring-boot3-starter sa-token-solon-plugin diff --git a/sa-token-starter/sa-token-spring-boot4-starter/pom.xml b/sa-token-starter/sa-token-spring-boot4-starter/pom.xml new file mode 100644 index 00000000..f6ce6e6f --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + + + cn.dev33 + sa-token-starter + ${revision} + ../pom.xml + + jar + + sa-token-spring-boot4-starter + sa-token-spring-boot4-starter + springboot4 integrate sa-token + + + 4.0.3 + + + + + + org.springframework.boot + spring-boot-starter-webmvc + + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + cn.dev33 + sa-token-jakarta-servlet + + + + + cn.dev33 + sa-token-spring-boot-autoconfig + + + cn.dev33 + sa-token-jackson + + + + + + + cn.dev33 + sa-token-jackson3 + + + + + + + + + + org.springframework.boot + spring-boot-starter + ${springboot4.version} + + + + org.springframework.boot + spring-boot-starter-webmvc + ${springboot4.version} + + + + org.springframework.boot + spring-boot-configuration-processor + ${springboot4.version} + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + + + diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java new file mode 100644 index 00000000..b279eef1 --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaFirewallCheckFilterForJakartaServlet.java @@ -0,0 +1,73 @@ +/* + * 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.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.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.annotation.Order; + +import java.io.IOException; + +/** + * 防火墙校验过滤器 (基于 Jakarta-Servlet) + * + * @author click33 + * @since 1.37.0 + */ +@Order(SaTokenConsts.FIREWALL_CHECK_FILTER_ORDER) +public class SaFirewallCheckFilterForJakartaServlet implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse res = (HttpServletResponse) response; + SaRequestForServlet saRequest = new SaRequestForServlet(req); + SaResponseForServlet saResponse = new SaResponseForServlet(res); + + try { + SaFirewallStrategy.instance.check.execute(saRequest, saResponse, null); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + SaJakartaServletOperateUtil.writeResult(response, e.getMessage()); + return; + } + catch (FirewallCheckException e) { + if(SaFirewallStrategy.instance.checkFailHandle == null) { + SaJakartaServletOperateUtil.writeResult(response, e.getMessage()); + } else { + SaFirewallStrategy.instance.checkFailHandle.run(e, saRequest, saResponse, null); + } + return; + } + // 更多异常则不处理,交由 Web 框架处理 + + // 向内执行 + chain.doFilter(request, response); + } + + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java new file mode 100644 index 00000000..7d3e6ff9 --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java @@ -0,0 +1,146 @@ +/* + * 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.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; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 全局鉴权过滤器 (基于 Jakarta-Servlet) + *

+ * 默认优先级为 -100,尽量保证在其它过滤器之前执行 + *

+ * + * @author click33 + * @since 1.34.0 + */ +@Order(SaTokenConsts.ASSEMBLY_ORDER) +public class SaServletFilter implements SaFilter, Filter { + + // ------------------------ 设置此过滤器 拦截 & 放行 的路由 + + /** + * 拦截路由 + */ + public List includeList = new ArrayList<>(); + + /** + * 放行路由 + */ + public List excludeList = new ArrayList<>(); + + @Override + public SaServletFilter addInclude(String... paths) { + includeList.addAll(Arrays.asList(paths)); + return this; + } + + @Override + public SaServletFilter addExclude(String... paths) { + excludeList.addAll(Arrays.asList(paths)); + return this; + } + + @Override + public SaServletFilter setIncludeList(List pathList) { + includeList = pathList; + return this; + } + + @Override + public SaServletFilter setExcludeList(List pathList) { + excludeList = pathList; + return this; + } + + + // ------------------------ 钩子函数 + + /** + * 认证函数:每次请求执行 + */ + public SaFilterAuthStrategy auth = r -> {}; + + /** + * 异常处理函数:每次[认证函数]发生异常时执行此函数 + */ + public SaFilterErrorStrategy error = e -> { + throw new SaTokenException(e); + }; + + /** + * 前置函数:在每次[认证函数]之前执行 + * 注意点:前置认证函数将不受 includeList 与 excludeList 的限制,所有路由的请求都会进入 beforeAuth + */ + public SaFilterAuthStrategy beforeAuth = r -> {}; + + @Override + public SaServletFilter setAuth(SaFilterAuthStrategy auth) { + this.auth = auth; + return this; + } + + @Override + public SaServletFilter setError(SaFilterErrorStrategy error) { + this.error = error; + return this; + } + + @Override + public SaServletFilter setBeforeAuth(SaFilterAuthStrategy beforeAuth) { + this.beforeAuth = beforeAuth; + return this; + } + + + // ------------------------ doFilter + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + try { + // 执行全局过滤器 + beforeAuth.run(null); + SaRouter.match(includeList).notMatch(excludeList).check(r -> { + auth.run(null); + }); + } + 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); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenContextFilterForJakartaServlet.java new file mode 100644 index 00000000..22dce8ce --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-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.SaTokenContextJakartaServletUtil; +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 { + SaTokenContextJakartaServletUtil.setContext((HttpServletRequest) request, (HttpServletResponse) response); + chain.doFilter(request, response); + } finally { + SaTokenContextJakartaServletUtil.clearContext(); + } + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java new file mode 100644 index 00000000..f0c04a99 --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/filter/SaTokenCorsFilterForJakartaServlet.java @@ -0,0 +1,55 @@ +/* + * 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.context.SaHolder; +import cn.dev33.satoken.context.model.SaTokenContextModelBox; +import cn.dev33.satoken.exception.BackResultException; +import cn.dev33.satoken.exception.StopMatchException; +import cn.dev33.satoken.servlet.util.SaJakartaServletOperateUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import jakarta.servlet.*; +import org.springframework.core.annotation.Order; + +import java.io.IOException; + +/** + * CORS 跨域策略过滤器 (基于 Jakarta-Servlet) + * + * @author click33 + * @since 1.42.0 + */ +@Order(SaTokenConsts.CORS_FILTER_ORDER) +public class SaTokenCorsFilterForJakartaServlet implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + try { + SaTokenContextModelBox box = SaHolder.getContext().getModelBox(); + SaStrategy.instance.corsHandle.execute(box.getRequest(), box.getResponse(), box.getStorage()); + } + catch (StopMatchException ignored) {} + catch (BackResultException e) { + SaJakartaServletOperateUtil.writeResult(response, e.getMessage()); + return; + } + + chain.doFilter(request, response); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java new file mode 100644 index 00000000..f42e892a --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java @@ -0,0 +1,122 @@ +/* + * 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.interceptor; + +import cn.dev33.satoken.exception.BackResultException; +import cn.dev33.satoken.exception.StopMatchException; +import cn.dev33.satoken.fun.SaParamFunction; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.lang.reflect.Method; + +/** + * Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力 + * + * @author click33 + * @since 1.34.0 + */ +public class SaInterceptor implements HandlerInterceptor { + + /** + * 是否打开注解鉴权 + */ + public boolean isAnnotation = true; + + /** + * 认证函数:每次请求执行 + *

参数:路由处理函数指针 + */ + public SaParamFunction auth = handler -> {}; + + /** + * 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 + */ + public SaInterceptor() { + } + + /** + * 创建一个 Sa-Token 综合拦截器,默认带有注解鉴权能力 + * @param auth 认证函数,每次请求执行 + */ + public SaInterceptor(SaParamFunction auth) { + this.auth = auth; + } + + /** + * 设置是否打开注解鉴权 + * @param isAnnotation / + * @return 对象自身 + */ + public SaInterceptor isAnnotation(boolean isAnnotation) { + this.isAnnotation = isAnnotation; + return this; + } + + /** + * 写入[认证函数]: 每次请求执行 + * @param auth / + * @return 对象自身 + */ + public SaInterceptor setAuth(SaParamFunction auth) { + this.auth = auth; + return this; + } + + + // ----------------- 验证方法 ----------------- + + /** + * 每次请求之前触发的方法 + */ + @Override + @SuppressWarnings("all") + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + try { + + // 这里必须确保 handler 是 HandlerMethod 类型时,才能进行注解鉴权 + if(isAnnotation && handler instanceof HandlerMethod) { + Method method = ((HandlerMethod) handler).getMethod(); + SaAnnotationStrategy.instance.checkMethodAnnotation.accept(method); + } + + // Auth 校验 + auth.run(handler); + + } catch (StopMatchException e) { + // StopMatchException 异常代表:停止匹配,进入Controller + + } catch (BackResultException e) { + // BackResultException 异常代表:停止匹配,向前端输出结果 + // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 back 前自行设置 Content-Type 为 application/json + // 例如:SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8"); + if(response.getContentType() == null) { + response.setContentType("text/plain; charset=utf-8"); + } + response.getWriter().print(e.getMessage()); + return false; + } + + // 通过验证 + return true; + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/package-info.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/package-info.java new file mode 100644 index 00000000..41194975 --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * Sa-Token 集成 SpringBoot4 的各个组件 + */ +package cn.dev33.satoken; diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java new file mode 100644 index 00000000..7ace87bf --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextForSpringInJakartaServlet.java @@ -0,0 +1,68 @@ +/* + * 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.SaTokenContextForReadOnly; +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; + +/** + *

此为低版本(<1.42.0) 的上下文处理方案,基于 Spring 内部工具类 RequestContextHolder 读写上下文,仅做留档,如无必要请勿使用

+ * + * Sa-Token 上下文处理器 [ SpringBoot4 Jakarta Servlet 版 ],在 SpringBoot4 中使用 Sa-Token 时,必须注入此实现类,否则会出现上下文无效异常 + * + * @author click33 + * @since 1.34.0 + */ +public class SaTokenContextForSpringInJakartaServlet implements SaTokenContextForReadOnly { + + /** + * 获取当前请求的 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 isValid() { + return SpringMVCUtil.isWeb(); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java new file mode 100644 index 00000000..4792da2d --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SaTokenContextRegister.java @@ -0,0 +1,70 @@ +/* + * 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.filter.SaFirewallCheckFilterForJakartaServlet; +import cn.dev33.satoken.filter.SaTokenContextFilterForJakartaServlet; +import cn.dev33.satoken.filter.SaTokenCorsFilterForJakartaServlet; +import cn.dev33.satoken.spring.pathmatch.SaPathPatternParserUtil; +import cn.dev33.satoken.strategy.SaStrategy; +import org.springframework.context.annotation.Bean; + +/** + * 注册 Sa-Token 框架所需要的 Bean + * + * @author click33 + * @since 1.34.0 + */ +public class SaTokenContextRegister { + + public SaTokenContextRegister() { + // 重写路由匹配算法 + SaStrategy.instance.routeMatcher = (pattern, path) -> { + return SaPathPatternParserUtil.match(pattern, path); + }; + } + + /** + * 上下文过滤器 + * + * @return / + */ + @Bean + public SaTokenContextFilterForJakartaServlet saTokenContextFilterForServlet() { + return new SaTokenContextFilterForJakartaServlet(); + } + + /** + * CORS 跨域策略过滤器 + * + * @return / + */ + @Bean + public SaTokenCorsFilterForJakartaServlet saTokenCorsFilterForJakartaServlet() { + return new SaTokenCorsFilterForJakartaServlet(); + } + + /** + * 防火墙过滤器 + * + * @return / + */ + @Bean + public SaFirewallCheckFilterForJakartaServlet saFirewallCheckFilterForJakartaServlet() { + return new SaFirewallCheckFilterForJakartaServlet(); + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java new file mode 100644 index 00000000..4f52cdca --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/java/cn/dev33/satoken/spring/SpringMVCUtil.java @@ -0,0 +1,67 @@ +/* + * 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.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 对象 + * + * @author click33 + * @since 1.34.0 + */ +public class SpringMVCUtil { + + private SpringMVCUtil() { + } + + /** + * 获取当前会话的 request + * @return request + */ + public static HttpServletRequest getRequest() { + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if(servletRequestAttributes == null) { + throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest"); + } + return servletRequestAttributes.getRequest(); + } + + /** + * 获取当前会话的 response + * @return response + */ + public static HttpServletResponse getResponse() { + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if(servletRequestAttributes == null) { + throw new NotWebContextException("非 web 上下文无法获取 HttpServletRequest"); + } + return servletRequestAttributes.getResponse(); + } + + /** + * 判断当前是否处于 Web 上下文中 + * @return request + */ + public static boolean isWeb() { + return RequestContextHolder.getRequestAttributes() != null; + } + +} diff --git a/sa-token-starter/sa-token-spring-boot4-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/sa-token-starter/sa-token-spring-boot4-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..4f9e5fdb --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot4-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.dev33.satoken.spring.SaTokenContextRegister