feat(B3): custom_css 站点级自定义样式-服务端黑名单强校验+5主题head内联直出

- validateConfigJson 增 custom_css 分支:≤10240字符;黑名单忽略大小写拒 </style/<script/@import/expression(
- 快照/渲染链路(model customCss)与 themeVarsCss 同构注入;缓存失效复用既有 SiteContentChangedEvent
- 5 套主题 head.html 于 main.css 与微调变量之后 th:utext 直出(安全性完全依赖服务端先行)
- SiteServiceIT+6 例(含 expression 红线项与 10240 边界);PortalSsrIT+3 例(渲染/head内/顺序/缓存失效)
- mvn -o test 258 例全绿(B3 状态,不含 B4 红测)
This commit is contained in:
chenxing
2026-09-07 20:14:23 +08:00
parent b4822a7f38
commit 19e414ee81
11 changed files with 190 additions and 0 deletions
@@ -95,6 +95,7 @@ public class PortalController {
model.addAttribute("site", site);
model.addAttribute("themeParams", site.getThemeParams());
model.addAttribute("themeVarsCss", site.getThemeVarsCss());
model.addAttribute("customCss", site.getCustomCss());
model.addAttribute("themeBase", "themes/" + site.getTheme());
model.addAttribute("navCategories", site.getCategories());
model.addAttribute("currentCategoryId", categoryId);
@@ -142,6 +143,7 @@ public class PortalController {
model.addAttribute("site", site);
model.addAttribute("themeParams", site.getThemeParams());
model.addAttribute("themeVarsCss", site.getThemeVarsCss());
model.addAttribute("customCss", site.getCustomCss());
model.addAttribute("themeBase", "themes/" + site.getTheme());
model.addAttribute("navCategories", site.getCategories());
model.addAttribute("currentCategoryId", detail.getCategoryId());
@@ -179,6 +181,7 @@ public class PortalController {
model.addAttribute("site", site);
model.addAttribute("themeParams", site.getThemeParams());
model.addAttribute("themeVarsCss", site.getThemeVarsCss());
model.addAttribute("customCss", site.getCustomCss());
model.addAttribute("themeBase", "themes/" + site.getTheme());
model.addAttribute("navCategories", site.getCategories());
model.addAttribute("q", q);
@@ -41,6 +41,7 @@ public class PortalPageRenderer {
model.addAttribute("site", site);
model.addAttribute("themeParams", site.getThemeParams());
model.addAttribute("themeVarsCss", site.getThemeVarsCss());
model.addAttribute("customCss", site.getCustomCss());
model.addAttribute("themeBase", "themes/" + site.getTheme());
model.addAttribute("navCategories", site.getCategories());
List<Map<String, Object>> banners = activeBanners(site, "home", url);