From 670eea97772c71fd354380a191869a9cd4b575a4 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Wed, 29 Apr 2026 20:40:54 +0800 Subject: [PATCH] =?UTF-8?q?--author:scott--date:20260429--for:=E3=80=90iss?= =?UTF-8?q?ues/9590=E3=80=91=E5=BE=AE=E6=9C=8D=E5=8A=A1nginx=E9=83=A8?= =?UTF-8?q?=E7=BD=B2openApi=E6=8E=A5=E5=8F=A3=E8=AE=BF=E9=97=AE=E4=B8=8D?= =?UTF-8?q?=E5=88=B0=EF=BC=8COpenAPI=E7=9A=84call=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E6=94=B9=E7=94=A8CommonUtils.getBaseUrl(request)=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E5=BE=AE=E6=9C=8D=E5=8A=A1=E7=BD=91=E5=85=B3base=20pa?= =?UTF-8?q?th=EF=BC=8C=E5=B9=B6=E6=94=AF=E6=8C=81originUrl=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E9=85=8D=E7=BD=AE=E5=AE=8C=E6=95=B4http(s)URL?= =?UTF-8?q?=E6=8C=87=E5=90=91=E5=85=B6=E4=BB=96=E5=BE=AE=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- .../openapi/controller/OpenApiController.java | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java index 62ad09193..13e782447 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java @@ -13,8 +13,8 @@ import org.jeecg.common.exception.JeecgBootBizTipException; import org.jeecg.common.system.base.controller.JeecgController; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.util.JwtUtil; +import org.jeecg.common.util.CommonUtils; import org.jeecg.common.util.RedisUtil; -import org.jeecg.common.util.RestUtil; import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.openapi.entity.OpenApi; import org.jeecg.modules.openapi.entity.OpenApiAuth; @@ -184,7 +184,17 @@ public class OpenApiController extends JeecgController httpHeaders.put("X-Access-Token", Lists.newArrayList(token)); httpHeaders.put("Content-Type",Lists.newArrayList("application/json")); HttpEntity httpEntity = new HttpEntity<>(json, httpHeaders); - url = RestUtil.getBaseUrl() + url; + //update-begin---author:scott ---date:20260429 for:【issues/9590】微服务nginx部署openApi接口访问不到----------- + // originUrl 支持两种形式: + // 1) 相对路径(如 /house/houseTest/list):拼接当前请求的 baseUrl; + // 使用 CommonUtils.getBaseUrl(request)(而非 RestUtil.getBaseUrl()), + // 可读取 X-Gateway-Base-Path 请求头,兼容微服务网关下的真实 base path + // 2) 完整URL(http(s)://host:port/path):直接使用,适用于微服务模式下接口部署在其他微服务模块(如 erp 7003)的场景 + String lowerUrl = url.toLowerCase(); + if (!lowerUrl.startsWith("http://") && !lowerUrl.startsWith("https://")) { + url = CommonUtils.getBaseUrl(request) + url; + } + //update-end---author:scott ---date:20260429 for:【issues/9590】微服务nginx部署openApi接口访问不到----------- UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url); if (HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method) @@ -231,7 +241,9 @@ public class OpenApiController extends JeecgController } /** - * 校验原始接口路径是否合法:必须以 / 开头,不允许 // 和 .. 防止路径穿越 + * 校验原始接口路径是否合法: + * - 相对路径:必须以 / 开头,不允许 // 和 .. 防止路径穿越 + * - 完整URL:仅允许 http/https 协议,禁止 file/ftp/gopher/jar/netdoc 等其它协议(用于微服务模式跨模块调用) */ private void validOriginUrl(String originUrl) { if (oConvertUtils.isEmpty(originUrl)) { @@ -245,21 +257,33 @@ public class OpenApiController extends JeecgController } catch (Exception e) { throw new JeecgBootBizTipException("原始接口路径包含非法字符"); } - if (!decoded.startsWith("/")) { - throw new JeecgBootBizTipException("原始接口路径必须以 / 开头"); - } - if (decoded.startsWith("//") || decoded.startsWith("/\\")) { - throw new JeecgBootBizTipException("原始接口路径不能以 // 或 /\\ 开头"); + //update-begin---author:scott ---date:20260429 for:【issues/9590】微服务nginx部署openApi接口访问不到----------- + // 微服务部署时,OpenAPI 配置的接口可能位于其他微服务模块(如 erp 7003),允许 originUrl 直接配置完整 http(s) URL + String lower = decoded.toLowerCase(); + boolean isFullHttpUrl = lower.startsWith("http://") || lower.startsWith("https://"); + if (!isFullHttpUrl) { + if (!decoded.startsWith("/")) { + throw new JeecgBootBizTipException("原始接口路径必须以 / 开头,或填写完整的 http(s) URL"); + } + if (decoded.startsWith("//") || decoded.startsWith("/\\")) { + throw new JeecgBootBizTipException("原始接口路径不能以 // 或 /\\ 开头"); + } + if (lower.contains("://") || lower.startsWith("file:") || lower.startsWith("ftp:") || lower.startsWith("gopher:") + || lower.startsWith("jar:") || lower.startsWith("netdoc:")) { + throw new JeecgBootBizTipException("原始接口路径仅支持相对路径或 http(s) 完整URL"); + } + } else { + // 即便是完整URL,也禁止其它危险协议(防止 http://x@file:/... 之类的绕过场景) + String afterScheme = lower.substring(lower.indexOf("://") + 3); + if (afterScheme.contains("file:") || afterScheme.contains("ftp:") || afterScheme.contains("gopher:") + || afterScheme.contains("jar:") || afterScheme.contains("netdoc:")) { + throw new JeecgBootBizTipException("原始接口路径不允许嵌套 file/ftp/gopher/jar/netdoc 等协议"); + } } if (decoded.contains("..")) { throw new JeecgBootBizTipException("原始接口路径不能包含 .."); } - String lower = decoded.toLowerCase(); - if (lower.contains("://") || lower.startsWith("http:") || lower.startsWith("https:") - || lower.startsWith("file:") || lower.startsWith("ftp:") || lower.startsWith("gopher:") - || lower.startsWith("jar:") || lower.startsWith("netdoc:")) { - throw new JeecgBootBizTipException("原始接口路径不允许包含协议"); - } + //update-end---author:scott ---date:20260429 for:【issues/9590】微服务nginx部署openApi接口访问不到----------- } @GetMapping("/json")