refactor(path): API 前缀收敛为 /api,退役 /{platform} 通配

- Config.API_PATH 由 "/{platform}" 改为 "/api",另留 MOBI_API_PATH 常量做对齐
- ManageAccessInterceptor 白名单改显式 /api 前缀,路径从通配变闭集
- DWebMvcConfig 拦截器注册由 /{platform}/** 改 /api/**,堵掉「任意前缀绕过白名单」的洞
This commit is contained in:
chenxing
2026-10-21 08:52:26 +08:00
parent 035df02f63
commit ad434dbc36
4 changed files with 15 additions and 12 deletions
@@ -19,7 +19,7 @@ import java.util.List;
* 白名单:GetUserInfo / GetUserScope / GetSysDict / RedirectTo(仅登录即可访问); * 白名单:GetUserInfo / GetUserScope / GetSysDict / RedirectTo(仅登录即可访问);
* env-config(免登录,SPA 启动阶段在 CAS 登录前就要拉运行时配置,且内容为非敏感前端配置, * env-config(免登录,SPA 启动阶段在 CAS 登录前就要拉运行时配置,且内容为非敏感前端配置,
* 端点由平台 yh-env-config-spring-boot-starter 提供,旁路过滤器见 EnvConfigSsoBypassFilter)。<br> * 端点由平台 yh-env-config-spring-boot-starter 提供,旁路过滤器见 EnvConfigSsoBypassFilter)。<br>
* 注册于 /{platform}/**(api/manage/mobiapi 三前缀均命中),排除 /oapi/**(服务间签名调用,行为不变)。<br> * 注册于 /api/**(显式前缀,路径闭集),排除 /oapi/**(服务间签名调用,行为不变)。<br>
* SUPER/BUREAU/SCHOOL 之间的细粒度差异由各 Controller 内 guard 实现。 * SUPER/BUREAU/SCHOOL 之间的细粒度差异由各 Controller 内 guard 实现。
* *
* @author chenx * @author chenx
@@ -29,17 +29,18 @@ import java.util.List;
public class ManageAccessInterceptor implements HandlerInterceptor { public class ManageAccessInterceptor implements HandlerInterceptor {
/** /**
* 白名单(Ant 风格,* 匹配 platform 前缀): * 白名单(显式 /api 前缀,路径闭集):
* 登录后骨架所需的 4 个只读接口——用户信息、访问范围、系统字典、跳转代理; * 登录后骨架所需的 4 个只读接口——用户信息、访问范围、系统字典、跳转代理;
* appearance 外观偏好读(仅登录即可读自身偏好,平台 yh-appearance-spring-boot-starter 端点);
* env-config 免登录(端点与默认路径见平台 yh-env-config-spring-boot-starter)。 * env-config 免登录(端点与默认路径见平台 yh-env-config-spring-boot-starter)。
*/ */
private static final List<String> WHITELIST = Arrays.asList( private static final List<String> WHITELIST = Arrays.asList(
"/*/base/GetUserInfo", "/api/base/GetUserInfo",
"/*/base/GetUserScope", "/api/base/GetUserScope",
"/*/base/GetSysDict", "/api/base/GetSysDict",
"/*/base/RedirectTo/*", "/api/base/RedirectTo/*",
"/api/appearance", "/api/appearance",
"/*/env-config"); "/api/env-config");
private static final AntPathMatcher MATCHER = new AntPathMatcher(); private static final AntPathMatcher MATCHER = new AntPathMatcher();
@@ -13,9 +13,10 @@ public enum Config
Inst; Inst;
// 末尾不要带斜杠:各控制器用 API_PATH + "/xxx/" 拼路径,若这里带尾斜杠会变成 // 末尾不要带斜杠:各控制器用 API_PATH + "/xxx/" 拼路径,若这里带尾斜杠会变成
// "/{platform}//xxx/" 这种字面双斜杠;Boot 2.6+ 默认 PathPatternParser 不合并连续斜杠, // "/api//xxx/" 这种字面双斜杠;Boot 2.6+ 默认 PathPatternParser 不合并连续斜杠,
// 会导致 /api/xxx 这类正常请求匹配不上而 404(旧 AntPathMatcher 会自动合并,故以前不报错)。 // 会导致 /api/xxx 这类正常请求匹配不上而 404(旧 AntPathMatcher 会自动合并,故以前不报错)。
public static final String API_PATH = "/{platform}"; // manage / api / mobiapi public static final String API_PATH = "/api"; // PC 管理端(CAS 会话),路径闭集:/manage 等旧前缀随之 404
public static final String MOBI_API_PATH = "/mobiapi"; // 移动端(平台 token;UserBase 自身不挂 mobiapi 控制器,仅供常量对齐)
public static final String OPEN_API_PATH = "/oapi/"; public static final String OPEN_API_PATH = "/oapi/";
public String getString(String key) public String getString(String key)
@@ -38,11 +38,12 @@ public class DWebMvcConfig implements WebMvcConfigurer
.addPathPatterns("/**") .addPathPatterns("/**")
.excludePathPatterns("/login", "/logout", "/static/**", "/error", "/upload/**"); .excludePathPatterns("/login", "/logout", "/static/**", "/error", "/upload/**");
// 管理端统一防线:NONE 级 403(白名单见拦截器内)。 // 管理端统一防线:NONE 级 403(白名单见拦截器内)。
// /{platform}/** 命中 api/manage/mobiapi 三前缀;显式排除 /oapi/**(服务间签名调用不受影响)。 // 注册 /api/**(显式前缀,路径闭集:/manage、/{platform} 通配退役,旧前缀随之 404,
// 同时堵掉"任意前缀绕过白名单"的洞);显式排除 /oapi/**(服务间签名调用不受影响)。
// /actuator/**:健康探针与 prometheus 抓取无登录态(projman 部署健康检查依赖,误拦会触发回滚); // /actuator/**:健康探针与 prometheus 抓取无登录态(projman 部署健康检查依赖,误拦会触发回滚);
// /v3/api-docs、/swagger-ui:接口文档工具链。 // /v3/api-docs、/swagger-ui:接口文档工具链。
registry.addInterceptor(manageAccessInterceptor) registry.addInterceptor(manageAccessInterceptor)
.addPathPatterns("/{platform}/**") .addPathPatterns("/api/**")
.excludePathPatterns("/oapi/**", "/login", "/logout", "/static/**", "/error", "/upload/**", .excludePathPatterns("/oapi/**", "/login", "/logout", "/static/**", "/error", "/upload/**",
"/actuator/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/doc.html", "/actuator/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/doc.html",
"/webjars/**"); "/webjars/**");
@@ -27,7 +27,7 @@ import java.util.TreeSet;
/** /**
* 缓存注册表对账接口(方案 C 的运行时可观测面)。<br><br> * 缓存注册表对账接口(方案 C 的运行时可观测面)。<br><br>
* *
* {@code GET /{platform}/cache/registry} 输出三块内容:<br> * {@code GET /api/cache/registry} 输出三块内容:<br>
* <ul> * <ul>
* <li><b>caches</b>:注册表({@link CacheNames#REGISTRY})逐项声明(TTL/抖动/存放/key 规则/失效责任/依赖表) * <li><b>caches</b>:注册表({@link CacheNames#REGISTRY})逐项声明(TTL/抖动/存放/key 规则/失效责任/依赖表)
* × 运行时是否已出现 × Caffeine 命中率统计(已 recordStats);</li> * × 运行时是否已出现 × Caffeine 命中率统计(已 recordStats);</li>