From 6f1094c361c4acdea8adfffae3e590a2163f8058 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Sun, 8 Dec 2024 11:17:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20SaFirewallStrategy?= =?UTF-8?q?=20=E9=98=B2=E7=81=AB=E5=A2=99=E7=AD=96=E7=95=A5=EF=BC=9A?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20path=20=E9=BB=91=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E3=80=81=E9=9D=9E=E6=B3=95=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E3=80=81=E7=99=BD=E5=90=8D=E5=8D=95=E6=94=BE?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/strategy/SaFirewallStrategy.java | 111 ++++++++++++++++++ .../cn/dev33/satoken/strategy/SaStrategy.java | 44 ------- .../java/com/pj/test/Test2Controller.java | 22 ++++ .../filter/SaPathCheckFilterForReactor.java | 8 +- .../filter/SaPathCheckFilterForReactor.java | 8 +- .../filter/SaPathCheckFilterForServlet.java | 8 +- .../SaPathCheckFilterForJakartaServlet.java | 8 +- 7 files changed, 149 insertions(+), 60 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaFirewallStrategy.java create mode 100644 sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/Test2Controller.java diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaFirewallStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaFirewallStrategy.java new file mode 100644 index 00000000..2a769392 --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaFirewallStrategy.java @@ -0,0 +1,111 @@ +/* + * 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.strategy; + +import cn.dev33.satoken.exception.RequestPathInvalidException; +import cn.dev33.satoken.fun.strategy.SaCheckRequestPathFunction; +import cn.dev33.satoken.fun.strategy.SaRequestPathInvalidHandleFunction; + +/** + * Sa-Token 防火墙策略 + * + * @author click33 + * @since 1.40.0 + */ +public final class SaFirewallStrategy { + + private SaFirewallStrategy() { + } + + /** + * 全局单例引用 + */ + public static final SaFirewallStrategy instance = new SaFirewallStrategy(); + + + // ----------------------- 所有策略 + + + /** + * 请求 path 黑名单 + */ + public String[] BLACK_PATHS = {}; + + /** + * 请求 path 白名单 + */ + public String[] WHITE_PATHS = {}; + + /** + * 请求 path 不允许出现的字符 + */ + public String[] INVALID_CHARACTER = { + "//", "\\", + "%2e", "%2E", // . + "%2f", "%2F", // / + "%5c", "%5C", // \ + "%25" // 空格 + }; + + /** + * 校验请求 path 的算法 + */ + public SaCheckRequestPathFunction checkRequestPath = (requestPath, extArg1, extArg2) -> { + // 1、如果在白名单里,则直接放行 + for (String item : WHITE_PATHS) { + if (requestPath.equals(item)) { + return; + } + } + + // 2、如果在黑名单里,则抛出异常 + for (String item : BLACK_PATHS) { + if (requestPath.equals(item)) { + throw new RequestPathInvalidException("非法请求:" + requestPath, requestPath); + } + } + + // 3、检查是否包含非法字符 + + // 不允许为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 校验不通过时处理方案的算法,自定义示例: + *
+	 * 		SaFirewallStrategy.instance.requestPathInvalidHandle = (e, extArg1, extArg2) -> {
+	 * 			// 自定义处理逻辑 ...
+	 *      };
+	 * 
+ */ + public SaRequestPathInvalidHandleFunction requestPathInvalidHandle = null; + + +} 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 3e12c8dd..16675f64 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,7 +16,6 @@ package cn.dev33.satoken.strategy; import cn.dev33.satoken.SaManager; -import cn.dev33.satoken.exception.RequestPathInvalidException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.fun.strategy.*; import cn.dev33.satoken.session.SaSession; @@ -164,49 +163,6 @@ 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-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 new file mode 100644 index 00000000..7b418278 --- /dev/null +++ b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/test/Test2Controller.java @@ -0,0 +1,22 @@ +package com.pj.test; + +import cn.dev33.satoken.util.SaResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 测试专用Controller + * @author click33 + * + */ +@RestController +public class Test2Controller { + + // 测试登录 ---- http://localhost:8081/.test + @RequestMapping("/.test") + public SaResult test2() { + System.out.println("--- 进来了"); + return SaResult.ok("登录成功"); + } + +} 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 index e1557d5e..55eeabcb 100644 --- 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 @@ -16,7 +16,7 @@ package cn.dev33.satoken.reactor.filter; import cn.dev33.satoken.exception.RequestPathInvalidException; -import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.strategy.SaFirewallStrategy; import cn.dev33.satoken.util.SaTokenConsts; import org.springframework.core.annotation.Order; import org.springframework.web.server.ServerWebExchange; @@ -38,13 +38,13 @@ public class SaPathCheckFilterForReactor implements WebFilter { // 校验本次请求 path 是否合法 try { - SaStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null); + SaFirewallStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null); } catch (RequestPathInvalidException e) { - if(SaStrategy.instance.requestPathInvalidHandle == null) { + if(SaFirewallStrategy.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); + SaFirewallStrategy.instance.requestPathInvalidHandle.run(e, exchange, null); } return Mono.empty(); } 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 index e1557d5e..55eeabcb 100644 --- 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 @@ -16,7 +16,7 @@ package cn.dev33.satoken.reactor.filter; import cn.dev33.satoken.exception.RequestPathInvalidException; -import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.strategy.SaFirewallStrategy; import cn.dev33.satoken.util.SaTokenConsts; import org.springframework.core.annotation.Order; import org.springframework.web.server.ServerWebExchange; @@ -38,13 +38,13 @@ public class SaPathCheckFilterForReactor implements WebFilter { // 校验本次请求 path 是否合法 try { - SaStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null); + SaFirewallStrategy.instance.checkRequestPath.run(exchange.getRequest().getPath().toString(), exchange, null); } catch (RequestPathInvalidException e) { - if(SaStrategy.instance.requestPathInvalidHandle == null) { + if(SaFirewallStrategy.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); + SaFirewallStrategy.instance.requestPathInvalidHandle.run(e, exchange, null); } return Mono.empty(); } 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 index 8334f69f..13bdda90 100644 --- 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 @@ -16,7 +16,7 @@ package cn.dev33.satoken.filter; import cn.dev33.satoken.exception.RequestPathInvalidException; -import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.strategy.SaFirewallStrategy; import cn.dev33.satoken.util.SaTokenConsts; import org.springframework.core.annotation.Order; @@ -39,14 +39,14 @@ public class SaPathCheckFilterForServlet implements Filter { // 校验本次请求 path 是否合法 try { HttpServletRequest req = (HttpServletRequest) request; - SaStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response); + SaFirewallStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response); } catch (RequestPathInvalidException e) { - if(SaStrategy.instance.requestPathInvalidHandle == null) { + if(SaFirewallStrategy.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); + SaFirewallStrategy.instance.requestPathInvalidHandle.run(e, request, response); } return; } 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 index 828adb7c..e13f13dd 100644 --- 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 @@ -16,7 +16,7 @@ package cn.dev33.satoken.filter; import cn.dev33.satoken.exception.RequestPathInvalidException; -import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.strategy.SaFirewallStrategy; import cn.dev33.satoken.util.SaTokenConsts; import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; @@ -39,14 +39,14 @@ public class SaPathCheckFilterForJakartaServlet implements Filter { // 校验本次请求 path 是否合法 try { HttpServletRequest req = (HttpServletRequest) request; - SaStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response); + SaFirewallStrategy.instance.checkRequestPath.run(req.getRequestURI(), request, response); } catch (RequestPathInvalidException e) { - if(SaStrategy.instance.requestPathInvalidHandle == null) { + if(SaFirewallStrategy.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); + SaFirewallStrategy.instance.requestPathInvalidHandle.run(e, request, response); } return; }