From 954efeb73277f924f836da2a25322ea35ee1bfa3 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Mon, 16 Oct 2023 16:02:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B7=AF=E7=94=B1=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E9=89=B4=E6=9D=83=E5=8F=AF=E8=A2=AB=E7=BB=95=E8=BF=87?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=20fix=20#515?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/application/ApplicationInfo.java | 45 ++++++++++++ .../RequestPathInvalidException.java | 46 +++++++++++++ .../strategy/SaCheckRequestPathFunction.java | 39 +++++++++++ .../SaRequestPathInvalidHandleFunction.java | 37 ++++++++++ .../cn/dev33/satoken/strategy/SaStrategy.java | 44 ++++++++++++ .../cn/dev33/satoken/util/SaTokenConsts.java | 22 ++++++ .../main/java/com/pj/test/TestController.java | 14 +++- .../src/main/resources/application.yml | 2 +- sa-token-demo/sa-token-demo-test/pom.xml | 1 + .../java/com/pj/current/NotFoundHandle.java | 2 +- .../main/java/com/pj/test/TestController.java | 11 +++ .../src/main/resources/application.yml | 2 +- .../SaTokenWebfluxSpringboot3Application.java | 3 +- .../src/main/resources/application.yml | 2 +- .../src/main/resources/application.yml | 2 +- .../servlet/model/SaRequestForServlet.java | 3 +- .../filter/SaPathCheckFilterForReactor.java | 56 +++++++++++++++ .../reactor/filter/SaReactorFilter.java | 4 +- .../reactor/model/SaRequestForReactor.java | 3 +- .../spring/SaTokenContextRegister.java | 11 +++ .../filter/SaPathCheckFilterForReactor.java | 56 +++++++++++++++ .../reactor/filter/SaReactorFilter.java | 23 +++---- .../reactor/model/SaRequestForReactor.java | 12 ++-- .../spring/SaTokenContextRegister.java | 14 +++- .../servlet/model/SaRequestForServlet.java | 24 +++---- .../dev33/satoken/spring/SaBeanRegister.java | 12 +++- .../path/ApplicationContextPathLoading.java | 68 +++++++++++++++++++ .../filter/SaPathCheckFilterForServlet.java | 68 +++++++++++++++++++ .../dev33/satoken/filter/SaServletFilter.java | 23 +++---- .../spring/SaTokenContextRegister.java | 14 +++- .../SaPathCheckFilterForJakartaServlet.java | 68 +++++++++++++++++++ .../dev33/satoken/filter/SaServletFilter.java | 22 +++--- .../spring/SaTokenContextRegister.java | 14 +++- 33 files changed, 688 insertions(+), 79 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/application/ApplicationInfo.java create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/exception/RequestPathInvalidException.java create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCheckRequestPathFunction.java create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRequestPathInvalidHandleFunction.java create mode 100644 sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java create mode 100644 sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java create mode 100644 sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/context/path/ApplicationContextPathLoading.java create mode 100644 sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForServlet.java create mode 100644 sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForJakartaServlet.java diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/application/ApplicationInfo.java b/sa-token-core/src/main/java/cn/dev33/satoken/application/ApplicationInfo.java new file mode 100644 index 00000000..93792d03 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/application/ApplicationInfo.java @@ -0,0 +1,45 @@ +/* + * 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.application; + +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * 应用全局信息 + * + * @author click33 + * @since 1.31.0 + */ +public class ApplicationInfo { + + /** + * 应用前缀 + */ + public static String routePrefix; + + /** + * 为指定 path 裁剪掉 routePrefix 前缀 + * @param path 指定 path + * @return / + */ + public static String cutPathPrefix(String path) { + if(! SaFoxUtil.isEmpty(routePrefix) && ! routePrefix.equals("/") && path.startsWith(routePrefix)){ + path = path.substring(routePrefix.length()); + } + return path; + } + +} \ No newline at end of file diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/exception/RequestPathInvalidException.java b/sa-token-core/src/main/java/cn/dev33/satoken/exception/RequestPathInvalidException.java new file mode 100644 index 00000000..e09cf9e0 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/exception/RequestPathInvalidException.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.exception; + +/** + * 一个异常:代表请求 path 无效或非法 + * + * @author click33 + * @since 1.37.0 + */ +public class RequestPathInvalidException extends SaTokenException { + + /** + * 序列化版本号 + */ + private static final long serialVersionUID = 8243974276159004739L; + + /** 具体无效的 path */ + private final String path; + + /** + * @return 具体无效的 path + */ + public String getPath() { + return path; + } + + public RequestPathInvalidException(String message, String path) { + super(message); + this.path = path; + } + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCheckRequestPathFunction.java b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCheckRequestPathFunction.java new file mode 100644 index 00000000..dcca032f --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaCheckRequestPathFunction.java @@ -0,0 +1,39 @@ +/* + * 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.fun.strategy; + +import cn.dev33.satoken.exception.RequestPathInvalidException; + +/** + * 函数式接口:校验请求 path 的算法 + * + *

如果属于无效请求 path,则抛出异常 RequestPathInvalidException

+ * + * @author click33 + * @since 1.37.0 + */ +@FunctionalInterface +public interface SaCheckRequestPathFunction { + + /** + * 执行函数 + * @param path 请求 path + * @param extArg1 扩展参数1 + * @param extArg2 扩展参数2 + */ + void run(String path, Object extArg1, Object extArg2); + +} \ No newline at end of file diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRequestPathInvalidHandleFunction.java b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRequestPathInvalidHandleFunction.java new file mode 100644 index 00000000..d3880465 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/fun/strategy/SaRequestPathInvalidHandleFunction.java @@ -0,0 +1,37 @@ +/* + * 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.fun.strategy; + +import cn.dev33.satoken.exception.RequestPathInvalidException; + +/** + * 函数式接口:当请求 path 校验不通过时处理方案的算法 + * + * @author click33 + * @since 1.37.0 + */ +@FunctionalInterface +public interface SaRequestPathInvalidHandleFunction { + + /** + * 执行函数 + * @param e 请求 path 无效的异常对象 + * @param extArg1 扩展参数1 + * @param extArg2 扩展参数2 + */ + void run(RequestPathInvalidException e, Object extArg1, Object extArg2); + +} \ No newline at end of file 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 d68a3ad3..06115533 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 @@ -18,6 +18,7 @@ package cn.dev33.satoken.strategy; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.annotation.*; import cn.dev33.satoken.basic.SaBasicUtil; +import cn.dev33.satoken.exception.RequestPathInvalidException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.fun.strategy.*; import cn.dev33.satoken.session.SaSession; @@ -329,6 +330,49 @@ public final class SaStrategy { return new StpLogic(loginType); }; + /** + * 请求 path 不允许出现的字符 + */ + public static String[] INVALID_CHARACTER = { + "//", "\\", + "%2e", "%2E", // . + "%2f", "%2F", // / + "%5c", "%5C", // \ + "%25" // 空格 + }; + + /** + * 校验请求 path 的算法 + */ + public SaCheckRequestPathFunction checkRequestPath = (requestPath, extArg1, extArg2) -> { + + // 不允许为null + if(requestPath == null) { + throw new RequestPathInvalidException("非法请求:null", null); + } + // 不允许包含非法字符 + for (String item : INVALID_CHARACTER) { + if (requestPath.contains(item)) { + throw new RequestPathInvalidException("非法请求:" + requestPath, requestPath); + } + } + // 不允许出现跨目录 + if(requestPath.contains("/.") || requestPath.contains("\\.")) { + throw new RequestPathInvalidException("非法请求:" + requestPath, requestPath); + } + }; + + + /** + * 当请求 path 校验不通过时处理方案的算法,自定义示例: + *
+	 * 		SaStrategy.instance.requestPathInvalidHandle = (e, extArg1, extArg2) -> {
+	 * 			// 自定义处理逻辑 ...
+	 *      };
+	 * 
+ */ + public SaRequestPathInvalidHandleFunction requestPathInvalidHandle = null; + // ----------------------- 重写策略 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 c2dcda2e..921d22ce 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 @@ -186,6 +186,28 @@ public class SaTokenConsts { */ public static final int ASSEMBLY_ORDER = -100; + /** + * 请求 path 校验过滤器的注册顺序 + */ + public static final int PATH_CHECK_FILTER_ORDER = -1000; + + /** + * Content-Type key + */ + public static final String CONTENT_TYPE_KEY = "Content-Type"; + + /** + * Content-Type text/plain; charset=utf-8 + */ + public static final String CONTENT_TYPE_TEXT_PLAIN = "text/plain; charset=utf-8"; + + /** + * Content-Type application/json;charset=UTF-8 + */ + public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json;charset=UTF-8"; + + + // =================== 废弃 =================== 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 065fa706..fc6d1844 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,10 +1,11 @@ package com.pj.test; +import cn.dev33.satoken.context.SaHolder; +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; -import cn.dev33.satoken.util.SaResult; - /** * 测试专用Controller * @author click33 @@ -27,4 +28,13 @@ public class TestController { return SaResult.ok(); } + // 测试 浏览器访问: http://localhost:8081/test/getRequestPath + @RequestMapping("getRequestPath") + public SaResult getRequestPath() { + System.out.println("-------------- 测试请求 path 获取"); + System.out.println("request.getRequestURI() " + SpringMVCUtil.getRequest().getRequestURI()); + System.out.println("saRequest.getRequestPath() " + SaHolder.getRequest().getRequestPath()); + return SaResult.ok(); + } + } diff --git a/sa-token-demo/sa-token-demo-springboot3-redis/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot3-redis/src/main/resources/application.yml index 1b1934e0..d872c2b8 100644 --- a/sa-token-demo/sa-token-demo-springboot3-redis/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-springboot3-redis/src/main/resources/application.yml @@ -19,7 +19,7 @@ sa-token: # 是否输出操作日志 is-log: true -spring: +spring: data: # redis配置 redis: diff --git a/sa-token-demo/sa-token-demo-test/pom.xml b/sa-token-demo/sa-token-demo-test/pom.xml index b614b20f..019ebfa7 100644 --- a/sa-token-demo/sa-token-demo-test/pom.xml +++ b/sa-token-demo/sa-token-demo-test/pom.xml @@ -11,6 +11,7 @@ org.springframework.boot spring-boot-starter-parent 2.5.14 + diff --git a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/current/NotFoundHandle.java b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/current/NotFoundHandle.java index 81ff22e8..0c5fa56b 100644 --- a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/current/NotFoundHandle.java +++ b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/current/NotFoundHandle.java @@ -23,5 +23,5 @@ public class NotFoundHandle implements ErrorController { response.setStatus(200); return SaResult.get(404, "not found", null); } - + } diff --git a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/TestController.java index 5dd97ced..800c0e31 100644 --- a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/TestController.java @@ -1,5 +1,7 @@ package com.pj.test; +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.spring.SpringMVCUtil; import cn.dev33.satoken.stp.SaLoginConfig; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaFoxUtil; @@ -41,4 +43,13 @@ public class TestController { return SaResult.ok(); } + // 测试 浏览器访问: http://localhost:8081/test/getRequestPath + @RequestMapping("getRequestPath") + public SaResult getRequestPath() { + System.out.println("------------ 测试访问路径获取 "); + System.out.println("SpringMVCUtil.getRequest().getRequestURI() " + SpringMVCUtil.getRequest().getRequestURI()); + System.out.println("SaHolder.getRequest().getRequestPath() " + SaHolder.getRequest().getRequestPath()); + return SaResult.ok(); + } + } diff --git a/sa-token-demo/sa-token-demo-test/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-test/src/main/resources/application.yml index cce187f4..92a664b2 100644 --- a/sa-token-demo/sa-token-demo-test/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-test/src/main/resources/application.yml @@ -19,7 +19,7 @@ sa-token: # 是否输出操作日志 is-log: true -spring: +spring: # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/java/com/pj/SaTokenWebfluxSpringboot3Application.java b/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/java/com/pj/SaTokenWebfluxSpringboot3Application.java index 10d78354..e6390aa0 100644 --- a/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/java/com/pj/SaTokenWebfluxSpringboot3Application.java +++ b/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/java/com/pj/SaTokenWebfluxSpringboot3Application.java @@ -1,10 +1,9 @@ package com.pj; +import cn.dev33.satoken.SaManager; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import cn.dev33.satoken.SaManager; - /** * Sa-Token整合webflux 示例 (springboot3) * diff --git a/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/resources/application.yml index 1828ff6a..ddf69276 100644 --- a/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-webflux-springboot3/src/main/resources/application.yml @@ -19,7 +19,7 @@ sa-token: # 是否输出操作日志 is-log: true -spring: +spring: # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml index 1828ff6a..ddf69276 100644 --- a/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml @@ -19,7 +19,7 @@ sa-token: # 是否输出操作日志 is-log: true -spring: +spring: # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-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 bd205eb4..57f7f216 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 @@ -16,6 +16,7 @@ package cn.dev33.satoken.servlet.model; import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.application.ApplicationInfo; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.servlet.error.SaServletErrorCode; @@ -124,7 +125,7 @@ public class SaRequestForServlet implements SaRequest { */ @Override public String getRequestPath() { - return request.getServletPath(); + return ApplicationInfo.cutPathPrefix(request.getRequestURI()); } /** diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java new file mode 100644 index 00000000..e1557d5e --- /dev/null +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java @@ -0,0 +1,56 @@ +/* + * 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.exception.RequestPathInvalidException; +import cn.dev33.satoken.strategy.SaStrategy; +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; + +/** + * 校验请求 path 是否合法 + * + * @author click33 + * @since 1.37.0 + */ +@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER) +public class SaPathCheckFilterForReactor implements WebFilter { + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + + // 校验本次请求 path 是否合法 + try { + SaStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null); + } catch (RequestPathInvalidException e) { + if(SaStrategy.instance.requestPathInvalidHandle == 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()))); + } else { + SaStrategy.instance.requestPathInvalidHandle.run(e, exchange, null); + } + return Mono.empty(); + } + + // 向下执行 + return chain.filter(exchange); + } + +} 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 944487eb..62556463 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 @@ -153,8 +153,8 @@ public class SaReactorFilter implements SaFilter, WebFilter { // 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("Content-Type") == null) { - exchange.getResponse().getHeaders().set("Content-Type", "text/plain; 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-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 c8680735..7b798cb9 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 @@ -17,6 +17,7 @@ package cn.dev33.satoken.reactor.model; import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.application.ApplicationInfo; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.reactor.context.SaReactorHolder; import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; @@ -112,7 +113,7 @@ public class SaRequestForReactor implements SaRequest { */ @Override public String getRequestPath() { - return request.getURI().getPath(); + return ApplicationInfo.cutPathPrefix(request.getPath().toString()); } /** 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 b4cf64be..12e25f6c 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 @@ -15,6 +15,7 @@ */ package cn.dev33.satoken.reactor.spring; +import cn.dev33.satoken.reactor.filter.SaPathCheckFilterForReactor; import org.springframework.context.annotation.Bean; import cn.dev33.satoken.context.SaTokenContext; @@ -37,4 +38,14 @@ public class SaTokenContextRegister { return new SaTokenContextForSpringReactor(); } + /** + * 请求 path 校验过滤器 + * + * @return / + */ + @Bean + public SaPathCheckFilterForReactor saPathCheckFilterForReactor() { + return new SaPathCheckFilterForReactor(); + } + } diff --git a/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java new file mode 100644 index 00000000..e1557d5e --- /dev/null +++ b/sa-token-starter/sa-token-reactor-spring-boot3-starter/src/main/java/cn/dev33/satoken/reactor/filter/SaPathCheckFilterForReactor.java @@ -0,0 +1,56 @@ +/* + * 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.exception.RequestPathInvalidException; +import cn.dev33.satoken.strategy.SaStrategy; +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; + +/** + * 校验请求 path 是否合法 + * + * @author click33 + * @since 1.37.0 + */ +@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER) +public class SaPathCheckFilterForReactor implements WebFilter { + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + + // 校验本次请求 path 是否合法 + try { + SaStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null); + } catch (RequestPathInvalidException e) { + if(SaStrategy.instance.requestPathInvalidHandle == 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()))); + } else { + SaStrategy.instance.requestPathInvalidHandle.run(e, exchange, null); + } + return Mono.empty(); + } + + // 向下执行 + return chain.filter(exchange); + } + +} 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 0236c343..276f8fa2 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 @@ -15,19 +15,10 @@ */ package cn.dev33.satoken.reactor.filter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import cn.dev33.satoken.filter.SaFilter; -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 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.reactor.context.SaReactorHolder; @@ -35,8 +26,16 @@ import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; import cn.dev33.satoken.reactor.error.SaReactorSpringBootErrorCode; import cn.dev33.satoken.router.SaRouter; 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; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * Reactor 全局鉴权过滤器 *

@@ -154,8 +153,8 @@ public class SaReactorFilter implements SaFilter, WebFilter { // 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("Content-Type") == null) { - exchange.getResponse().getHeaders().set("Content-Type", "text/plain; 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/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 4a85b97b..c8a5c588 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 @@ -16,16 +16,16 @@ package cn.dev33.satoken.reactor.model; -import org.springframework.http.HttpCookie; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilterChain; - import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.application.ApplicationInfo; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.reactor.context.SaReactorHolder; import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; import cn.dev33.satoken.util.SaFoxUtil; +import org.springframework.http.HttpCookie; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilterChain; import java.util.ArrayList; import java.util.List; @@ -113,7 +113,7 @@ public class SaRequestForReactor implements SaRequest { */ @Override public String getRequestPath() { - return request.getURI().getPath(); + return ApplicationInfo.cutPathPrefix(request.getPath().toString()); } /** 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 059ae1a5..1644f11d 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,9 +15,9 @@ */ package cn.dev33.satoken.reactor.spring; -import org.springframework.context.annotation.Bean; - import cn.dev33.satoken.context.SaTokenContext; +import cn.dev33.satoken.reactor.filter.SaPathCheckFilterForReactor; +import org.springframework.context.annotation.Bean; /** * 注册 Sa-Token 所需要的 Bean @@ -37,4 +37,14 @@ public class SaTokenContextRegister { return new SaTokenContextForSpringReactor(); } + /** + * 请求 path 校验过滤器 + * + * @return / + */ + @Bean + public SaPathCheckFilterForReactor saPathCheckFilterForReactor() { + return new SaPathCheckFilterForReactor(); + } + } 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 d3f0d2e7..d1228b51 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 @@ -15,19 +15,19 @@ */ package cn.dev33.satoken.servlet.model; -import java.io.IOException; -import java.util.*; +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.application.ApplicationInfo; +import cn.dev33.satoken.context.model.SaRequest; +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.servlet.error.SaServletErrorCode; +import cn.dev33.satoken.util.SaFoxUtil; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import cn.dev33.satoken.SaManager; -import cn.dev33.satoken.context.model.SaRequest; -import cn.dev33.satoken.exception.SaTokenException; -import cn.dev33.satoken.servlet.error.SaServletErrorCode; -import cn.dev33.satoken.util.SaFoxUtil; +import java.io.IOException; +import java.util.*; /** * 对 SaRequest 包装类的实现(Servlet 版) @@ -41,15 +41,15 @@ public class SaRequestForServlet implements SaRequest { * 底层Request对象 */ protected HttpServletRequest request; - + /** * 实例化 - * @param request request对象 + * @param request request对象 */ public SaRequestForServlet(HttpServletRequest request) { this.request = request; } - + /** * 获取底层源对象 */ @@ -125,7 +125,7 @@ public class SaRequestForServlet implements SaRequest { */ @Override public String getRequestPath() { - return request.getServletPath(); + return ApplicationInfo.cutPathPrefix(request.getRequestURI()); } /** diff --git a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanRegister.java b/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanRegister.java index 1c96d687..57c28357 100644 --- a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanRegister.java +++ b/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/SaBeanRegister.java @@ -15,6 +15,7 @@ */ package cn.dev33.satoken.spring; +import cn.dev33.satoken.spring.context.path.ApplicationContextPathLoading; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -50,5 +51,14 @@ public class SaBeanRegister { public SaJsonTemplate getSaJsonTemplateForJackson() { return new SaJsonTemplateForJackson(); } - + + /** + * 应用上下文路径加载器 + * @return / + */ + @Bean + public ApplicationContextPathLoading getApplicationContextPathLoading() { + return new ApplicationContextPathLoading(); + } + } diff --git a/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/context/path/ApplicationContextPathLoading.java b/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/context/path/ApplicationContextPathLoading.java new file mode 100644 index 00000000..9ce85586 --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot-autoconfig/src/main/java/cn/dev33/satoken/spring/context/path/ApplicationContextPathLoading.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.context.path; + +import cn.dev33.satoken.application.ApplicationInfo; +import cn.dev33.satoken.util.SaFoxUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; + +/** + * 应用上下文路径加载器 + * + * @author click33 + * @since 1.37.0 + */ +public class ApplicationContextPathLoading implements ApplicationRunner { + + @Value("${server.servlet.context-path:}") + String contextPath; + + @Value("${spring.mvc.servlet.path:}") + String servletPath; + + @Override + public void run(ApplicationArguments args) throws Exception { + + String routePrefix = ""; + + if(SaFoxUtil.isNotEmpty(contextPath)) { + if(! contextPath.startsWith("/")){ + contextPath = "/" + contextPath; + } + if (contextPath.endsWith("/")) { + contextPath = contextPath.substring(0, contextPath.length() - 1); + } + routePrefix += contextPath; + } + + if(SaFoxUtil.isNotEmpty(servletPath)) { + if(! servletPath.startsWith("/")){ + servletPath = "/" + servletPath; + } + if (servletPath.endsWith("/")) { + servletPath = servletPath.substring(0, servletPath.length() - 1); + } + routePrefix += servletPath; + } + + if(SaFoxUtil.isNotEmpty(routePrefix) && ! routePrefix.equals("/") ){ + ApplicationInfo.routePrefix = routePrefix; + } + } + +} \ No newline at end of file diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForServlet.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForServlet.java new file mode 100644 index 00000000..8334f69f --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForServlet.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.filter; + +import cn.dev33.satoken.exception.RequestPathInvalidException; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import org.springframework.core.annotation.Order; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * 校验请求 path 是否合法 + * + * @author click33 + * @since 1.37.0 + */ +@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER) +public class SaPathCheckFilterForServlet implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + // 校验本次请求 path 是否合法 + try { + HttpServletRequest req = (HttpServletRequest) request; + SaStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response); + } catch (RequestPathInvalidException e) { + if(SaStrategy.instance.requestPathInvalidHandle == null) { + response.setContentType("text/plain; charset=utf-8"); + response.getWriter().print(e.getMessage()); + response.getWriter().flush(); + } else { + SaStrategy.instance.requestPathInvalidHandle.run(e, request, response); + } + return; + } + + // 向下执行 + 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 7cc77e38..8fd3eb9f 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,26 +15,19 @@ */ package cn.dev33.satoken.filter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -import org.springframework.core.annotation.Order; - 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.util.SaTokenConsts; +import org.springframework.core.annotation.Order; + +import javax.servlet.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Servlet 全局鉴权过滤器 @@ -147,7 +140,7 @@ public class SaServletFilter implements SaFilter, Filter { // 请注意此处默认 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("text/plain; charset=utf-8"); + response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN); } response.getWriter().print(result); return; 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 c380827c..fa24e0d9 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,9 +15,9 @@ */ package cn.dev33.satoken.spring; -import org.springframework.context.annotation.Bean; - import cn.dev33.satoken.context.SaTokenContext; +import cn.dev33.satoken.filter.SaPathCheckFilterForServlet; +import org.springframework.context.annotation.Bean; /** * 注册 Sa-Token 框架所需要的 Bean @@ -37,4 +37,14 @@ public class SaTokenContextRegister { return new SaTokenContextForSpring(); } + /** + * 请求 path 校验过滤器 + * + * @return / + */ + @Bean + public SaPathCheckFilterForServlet saPathCheckFilterForServlet() { + return new SaPathCheckFilterForServlet(); + } + } diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForJakartaServlet.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForJakartaServlet.java new file mode 100644 index 00000000..828adb7c --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaPathCheckFilterForJakartaServlet.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.filter; + +import cn.dev33.satoken.exception.RequestPathInvalidException; +import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.util.SaTokenConsts; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.annotation.Order; + +import java.io.IOException; + +/** + * 校验请求 path 是否合法 + * + * @author click33 + * @since 1.37.0 + */ +@Order(SaTokenConsts.PATH_CHECK_FILTER_ORDER) +public class SaPathCheckFilterForJakartaServlet implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + // 校验本次请求 path 是否合法 + try { + HttpServletRequest req = (HttpServletRequest) request; + SaStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response); + } catch (RequestPathInvalidException e) { + if(SaStrategy.instance.requestPathInvalidHandle == null) { + response.setContentType("text/plain; charset=utf-8"); + response.getWriter().print(e.getMessage()); + response.getWriter().flush(); + } else { + SaStrategy.instance.requestPathInvalidHandle.run(e, request, response); + } + 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/SaServletFilter.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/filter/SaServletFilter.java index bbfcc4f3..e634a097 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,25 +15,19 @@ */ package cn.dev33.satoken.filter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.springframework.core.annotation.Order; - 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.util.SaTokenConsts; -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.FilterConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; +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; /** * Servlet 全局鉴权过滤器 @@ -146,7 +140,7 @@ public class SaServletFilter implements SaFilter, Filter { // 请注意此处默认 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("text/plain; charset=utf-8"); + response.setContentType(SaTokenConsts.CONTENT_TYPE_TEXT_PLAIN); } response.getWriter().print(result); return; 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 0f881a0f..d8ab7b98 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,9 +15,9 @@ */ package cn.dev33.satoken.spring; -import org.springframework.context.annotation.Bean; - import cn.dev33.satoken.context.SaTokenContext; +import cn.dev33.satoken.filter.SaPathCheckFilterForJakartaServlet; +import org.springframework.context.annotation.Bean; /** * 注册 Sa-Token 框架所需要的 Bean @@ -37,4 +37,14 @@ public class SaTokenContextRegister { return new SaTokenContextForSpringInJakartaServlet(); } + /** + * 请求 path 校验过滤器 + * + * @return / + */ + @Bean + public SaPathCheckFilterForJakartaServlet saPathCheckFilterForJakartaServlet() { + return new SaPathCheckFilterForJakartaServlet(); + } + }