bean = new FilterRegistrationBean<>();
- bean.setFilter(new SignKeyInternalIpFilter(properties));
- bean.addUrlPatterns("/oapi/internal/*");
- bean.setOrder(Ordered.HIGHEST_PRECEDENCE + 9);
- return bean;
- }
-
/**
* UserBase 本地 CAS 登录用户提供者:按登录名/手机号查 UserBase 自身库返回 BoaUser。
* 加 {@code @Primary} 稳定覆盖 yh-auth 默认 NoOp 实现;bean 名固定=userDetailsProvider,
diff --git a/src/main/java/com/yunhai/userbase/config/SignKeyInternalIpFilter.java b/src/main/java/com/yunhai/userbase/config/SignKeyInternalIpFilter.java
deleted file mode 100644
index 2359640..0000000
--- a/src/main/java/com/yunhai/userbase/config/SignKeyInternalIpFilter.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.yunhai.userbase.config;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.filter.OncePerRequestFilter;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
-
-/**
- * 内部开放接口(/oapi/internal/*)来源 IP 白名单过滤器。
- * 防止密钥兜底端点(/oapi/internal/sign-key/{appId})被公网直接枚举调用;
- * 只允许内网 / 显式配置的白名单来源通过,未命中返回 403。
- * 支持 X-Forwarded-For / X-Real-IP 等常见代理头解析,取最左侧真实来源 IP 做校验。
- */
-public class SignKeyInternalIpFilter extends OncePerRequestFilter {
-
- private static final Logger log = LoggerFactory.getLogger(SignKeyInternalIpFilter.class);
-
- private final SignKeyInternalProperties properties;
-
- public SignKeyInternalIpFilter(SignKeyInternalProperties properties) {
- this.properties = properties;
- }
-
- @Override
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- if (!properties.isEnabled()) {
- filterChain.doFilter(request, response);
- return;
- }
- String sourceIp = resolveSourceIp(request);
- List effectiveIps = properties.getEffectiveIps();
- if (CollectionUtils.isEmpty(effectiveIps) || matchAny(sourceIp, effectiveIps)) {
- filterChain.doFilter(request, response);
- return;
- }
- log.warn("[SignKeyInternal] 拒绝非白名单来源访问内部接口: uri={}, sourceIp={}, whitelist={}",
- request.getRequestURI(), sourceIp, effectiveIps);
- response.setStatus(HttpServletResponse.SC_FORBIDDEN);
- response.setContentType("application/json;charset=UTF-8");
- response.getWriter().write("{\"code\":403,\"msg\":\"内部接口不允许从该来源访问\",\"data\":null}");
- response.getWriter().flush();
- }
-
- private static String resolveSourceIp(HttpServletRequest request) {
- String[] headers = new String[] {
- "X-Forwarded-For",
- "X-Real-IP",
- "Proxy-Client-IP",
- "WL-Proxy-Client-IP",
- "HTTP_CLIENT_IP",
- "HTTP_X_FORWARDED_FOR"
- };
- for (String header : headers) {
- String raw = request.getHeader(header);
- if (raw == null || raw.isEmpty() || "unknown".equalsIgnoreCase(raw)) {
- continue;
- }
- // X-Forwarded-For 可能是 多个IP逗号分隔,取最左侧
- String first = raw.split(",")[0].trim();
- if (!first.isEmpty()) {
- return first;
- }
- }
- return request.getRemoteAddr();
- }
-
- private static boolean matchAny(String ip, List cidrs) {
- for (String cidr : cidrs) {
- if (matchCidr(ip, cidr)) {
- return true;
- }
- }
- return false;
- }
-
- private static boolean matchCidr(String ip, String cidr) {
- if (ip == null || cidr == null) {
- return false;
- }
- try {
- int prefixLen;
- String network;
- if (cidr.contains("/")) {
- String[] parts = cidr.split("/");
- network = parts[0].trim();
- prefixLen = Integer.parseInt(parts[1].trim());
- } else {
- network = cidr.trim();
- // 判断地址族决定默认前缀长度
- InetAddress na = InetAddress.getByName(network);
- prefixLen = (na instanceof Inet6Address) ? 128 : 32;
- }
- InetAddress ipAddr = InetAddress.getByName(ip);
- InetAddress netAddr = InetAddress.getByName(network);
- if (ipAddr.getClass() != netAddr.getClass()) {
- return false;
- }
- byte[] ipBytes = ipAddr.getAddress();
- byte[] netBytes = netAddr.getAddress();
- int bits = prefixLen;
- for (int i = 0; i < ipBytes.length && bits > 0; i++) {
- int mask = bits >= 8 ? 0xFF : (0xFF << (8 - bits));
- if ((ipBytes[i] & mask) != (netBytes[i] & mask)) {
- return false;
- }
- bits -= 8;
- }
- return true;
- } catch (UnknownHostException | NumberFormatException ignored) {
- return false;
- }
- }
-}
diff --git a/src/main/java/com/yunhai/userbase/config/SignKeyInternalProperties.java b/src/main/java/com/yunhai/userbase/config/SignKeyInternalProperties.java
deleted file mode 100644
index f5eb76b..0000000
--- a/src/main/java/com/yunhai/userbase/config/SignKeyInternalProperties.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.yunhai.userbase.config;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * 内部开放接口(/oapi/internal/*)访问白名单 IP 配置。
- * 支持单 IP、CIDR(如 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、127.0.0.1/32)。
- *
- * 可在 Nacos 上配置,例如:
- * yh:
- * sign-key-internal:
- * ips:
- * - 10.0.0.0/8
- * - 172.16.0.0/12
- * - 192.168.0.0/16
- * - 127.0.0.1/32
- * - 172.20.10.5/32 # 某台固定机器
- *
- * 未配置时,默认允许 10/172.16-31/192.168 私有段 + 127.0.0.1(方便本地开发/内网部署)。
- */
-@ConfigurationProperties(prefix = "yh.sign-key-internal")
-public class SignKeyInternalProperties {
-
- /** 显式允许的来源 IP(CIDR 或 单 IP)。为空时使用默认私有段规则。 */
- private List ips = new ArrayList<>();
-
- /** 是否启用白名单校验;设置 false 可临时关闭(生产不建议)。 */
- private boolean enabled = true;
-
- public List getIps() { return ips; }
-
- public void setIps(List ips) { this.ips = ips; }
-
- public boolean isEnabled() { return enabled; }
-
- public void setEnabled(boolean enabled) { this.enabled = enabled; }
-
- /** 未配置 ips 时返回默认私有段 + localhost 规则。 */
- public List getEffectiveIps() {
- if (ips != null && !ips.isEmpty()) {
- return ips;
- }
- return Arrays.asList(
- "10.0.0.0/8",
- "172.16.0.0/12",
- "192.168.0.0/16",
- "127.0.0.1/32",
- "0:0:0:0:0:0:0:1/128"
- );
- }
-}
diff --git a/src/main/java/com/yunhai/userbase/controller/oapi/SignKeyInternalController.java b/src/main/java/com/yunhai/userbase/controller/oapi/SignKeyInternalController.java
deleted file mode 100644
index b435789..0000000
--- a/src/main/java/com/yunhai/userbase/controller/oapi/SignKeyInternalController.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.yunhai.userbase.controller.oapi;
-
-import com.yunhai.platform.appauth.AppAuthProperties;
-import com.yunhai.userbase.config.Config;
-import com.yunhai.userbase.entity.ApplicationInfo;
-import com.yunhai.userbase.repository.ApplicationInfoRepository;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * 验签兜底端点:供其他业务服务在「共享 Redis 宕机且本地缓存也未命中」时直连获取某应用的密钥。
- * 直接从 MySQL 读(绕过可能同宕的共享 Redis),是密钥的权威源;写入侧仍由
- * {@code SignKeyCacheService} 同步到 Redis。返回形状与 BasePlatform 读侧解析契约一致:
- * {@code {"appKey":"100616","secret":"...","enabled":true}}。
- * 解析优先级:
- * 1) 本库 application_info(覆盖全部「已颁发」应用的实时密钥);
- * 2) 配置式受信应用 {@code yh.app-auth.trusted-apps}(平台自身默认密钥,如 应用中心 100616,
- * 即便尚未落库也可解析,避免「默认 appKey 未建行」时此处返回 404 导致验签链路失败);
- * 两者皆无 → 404。
- * 注意:此端点返回的是应用密钥,必须仅内网可达(由部署网络隔离保障),切勿暴露到公网。
- */
-@RestController
-@RequestMapping(Config.OPEN_API_PATH + "internal")
-public class SignKeyInternalController {
-
- private final ApplicationInfoRepository applicationInfoRepository;
- private final AppAuthProperties appAuthProperties;
-
- public SignKeyInternalController(ApplicationInfoRepository applicationInfoRepository,
- AppAuthProperties appAuthProperties) {
- this.applicationInfoRepository = applicationInfoRepository;
- this.appAuthProperties = appAuthProperties;
- }
-
- @GetMapping("sign-key/{appId}")
- public ResponseEntity