feat(图标库): 支持第三方库直传 SVG 字符串校验(新增 parse-svg-text, PR #3437)
图标新增除上传文件外,前端可从第三方图标库直接选取(已是字符串)。 新增 POST /admin/icon/parse-svg-text 做入库前预校验(同 parse-svg 安全口径); 第三方库字符串也可直接走 POST /admin/icon/item 保存(保存接口本就同款校验)。 测试服实测通过(合法200/script拒210757/空白400/中文按字节计)。
这个提交包含在:
父节点
82f257b950
当前提交
fca672aaf1
@ -0,0 +1,175 @@
|
||||
# 【新增接口·管理后台】图标库 新增 parse-svg-text(支持第三方图标库直传 SVG 字符串校验)
|
||||
|
||||
> **PR**: #3437 | **关联工单**: #3434
|
||||
> **服务**: hl-user-service | **更新时间**: 2026-06-04
|
||||
>
|
||||
> **存放目录**: `changelogs-v2/2026-06/`
|
||||
> **影响范围**: 管理后台「图标库」图标新增/编辑页——新增图标的「来源」除「上传 SVG 文件」外,新增「从第三方图标库选取」路径
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键说明
|
||||
|
||||
1. **新输入路径**:前端反馈,除了上传 `.svg` 文件,运营还可以从前端集成的**第三方图标库**(iconfont / 图标组件库等)直接选取图标,此时前端**已经拿到 SVG 字符串**,无需"上传文件 → 后端解析"这一步。
|
||||
|
||||
2. **两条保存路径都支持,二选一**:
|
||||
|
||||
| 路径 | 调用 | 适用 |
|
||||
|---|---|---|
|
||||
| A. 直接保存 | `POST /admin/icon/item`(`svgContent` 直接传字符串) | 第三方库字符串**本就能直接保存**——保存接口的 `svgContent` 一直是字符串字段,且后端保存时第一步即做同款安全校验 |
|
||||
| B. 先预校验再保存(**推荐**) | `POST /admin/icon/parse-svg-text` 预校验 → 填表单 → `POST /admin/icon/item` 保存 | 与「上传文件」路径(`parse-svg` → 保存)UX 对称,**错误早暴露**:含 `<script>`/DOCTYPE 等浏览器能渲染、后端会拒的内容,选取后立即报错,不必等填完整张表单点保存才发现 |
|
||||
|
||||
3. **安全口径完全一致**:`parse-svg-text` 与文件路径 `parse-svg`、以及保存接口共用**同一套**服务端校验(XXE-safe 解析 + 拒 `<script>`/`<foreignObject>`/`on*` 事件属性/`javascript:` 外链 + ≤256KB)。`parse-svg-text` **仅校验、不落库**;落库仍走保存接口(保存时二次校验,纵深防御)。前端内联渲染 SVG 时**仍建议先做一次 sanitize**。
|
||||
|
||||
4. 本次**纯加性**:不改动任何已有端点(`parse-svg` / `item` / 查询等契约全部不变)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 接口背景
|
||||
|
||||
图标库新增图标原流程(上传文件):
|
||||
|
||||
```
|
||||
上传 .svg 文件 → POST /admin/icon/parse-svg(解析+校验,返回字符串)→ 回填表单 → POST /admin/icon/item(保存)
|
||||
```
|
||||
|
||||
新增「第三方库选取」路径,前端已持有字符串,对称流程:
|
||||
|
||||
```
|
||||
第三方库选取(拿到 SVG 字符串)→ POST /admin/icon/parse-svg-text(校验,返回字符串)→ 回填表单 → POST /admin/icon/item(保存)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| # | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|----------|------|
|
||||
| 1 | POST | `/admin/icon/parse-svg-text` | **新增** | 校验前端直传的 SVG 字符串(来自第三方库),仅校验不落库 |
|
||||
|
||||
> 网关路由 `/admin/icon/**` 已是通配,本端点自动覆盖,无需前端额外处理路由。
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口详情
|
||||
|
||||
### 3.1 校验前端直传的 SVG 字符串
|
||||
|
||||
**POST** `/admin/icon/parse-svg-text`
|
||||
|
||||
- **使用场景**:从第三方图标库选取图标(已是字符串)后,保存前做合法性 + 安全校验
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:是(仅校验,不落库)
|
||||
|
||||
**Body 入参**(`IconSvgParseTextReqVO`):
|
||||
|
||||
| 字段 | 类型 | 必填 | 校验 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `svgContent` | string | ✅ | `@NotBlank` + `@Size(max=262144)` | 第三方库选取的原始 SVG 字符串(UTF-8 文本) |
|
||||
|
||||
**出参**:`Result<IconSvgParseRespVO>`(与 `parse-svg` 复用同一响应 VO)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `svgContent` | string | 校验通过的 SVG 字符串(原样回填保存表单) |
|
||||
| `fileName` | string | **恒为 `null`**(非文件来源,仅文件上传路径才有值) |
|
||||
| `size` | long | 内容**字节数(UTF-8 编码)**,非字符数 |
|
||||
|
||||
**典型示例 请求**:
|
||||
```bash
|
||||
curl -X POST "https://api.test.1814.love:9443/admin/icon/parse-svg-text" \
|
||||
-H "Authorization: Bearer <adminToken>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"svgContent":"<svg viewBox=\"0 0 24 24\"><path d=\"M0 0h24v24H0z\"/></svg>"}'
|
||||
```
|
||||
|
||||
**典型示例 响应**(测试服实测):
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"svgContent": "<svg viewBox=\"0 0 24 24\"><path d=\"M0 0h24v24H0z\"/></svg>",
|
||||
"fileName": null,
|
||||
"size": 56
|
||||
},
|
||||
"message": "成功"
|
||||
}
|
||||
```
|
||||
|
||||
**异常 响应**(SVG 含脚本/事件/外链,测试服实测):
|
||||
```json
|
||||
{ "code": 210757, "message": "SVG 含不安全内容(脚本/事件/外链),请清理后重试", "data": null }
|
||||
```
|
||||
|
||||
**异常 响应**(svgContent 为空/纯空白,@NotBlank 拦截):
|
||||
```json
|
||||
{ "code": 400, "message": "SVG 内容不能为空", "data": null }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 保存图标(已有接口,未变,此处仅提示第三方库路径如何用)
|
||||
|
||||
**POST** `/admin/icon/item`
|
||||
|
||||
第三方库选取的字符串可**直接**作为 `svgContent` 传入保存,无需先上传成文件。保存接口本就对 `svgContent` 做同款安全校验(见 §6 错误码)。完整字段契约见图标库模块首推 changelog `03_3390_图标库模块...` §3.6,本次未改动。
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端动作(mmg)
|
||||
|
||||
1. **图标新增/编辑页加"来源"选择**:现有「上传 SVG 文件」之外,加「从第三方图标库选取」。
|
||||
2. **第三方库选取后(推荐路径 B)**:拿到 SVG 字符串 → 调 `POST /admin/icon/parse-svg-text` 预校验 → 成功则用返回的 `svgContent` 回填表单(同上传文件路径的回填逻辑)→ 失败则按 §6 错误码提示用户更换图标。
|
||||
3. **或直接保存(路径 A)**:若不想加预校验步骤,可把第三方库字符串直接放进 `POST /admin/icon/item` 的 `svgContent`,保存接口会做同款校验并返回对应错误码。
|
||||
4. **渲染仍建议 sanitize**:后端已拒明显恶意内容,前端内联渲染(`v-html`/`innerHTML`)时再做一次 sanitize 作纵深防御。
|
||||
|
||||
---
|
||||
|
||||
## 5. 枚举 / 数据字典
|
||||
|
||||
无新增枚举。本端点不涉及状态/类型字段。
|
||||
|
||||
---
|
||||
|
||||
## 6. 错误码
|
||||
|
||||
| code | 含义 | 触发条件 | 涉及接口 |
|
||||
|---|---|---|---|
|
||||
| 400 | 参数校验失败 | `svgContent` 为空/纯空白(`@NotBlank`)或超 `@Size(262144)` | §3.1 |
|
||||
| 401 | 未登录 | admin JWT 无效或缺失 | §3.1 |
|
||||
| **210754** | SVG 内容不合法 | 非合法 XML 或根元素不是 `<svg>` | §3.1 §3.2 |
|
||||
| **210755** | SVG 内容过大 | 超过 256KB(按 UTF-8 字节) | §3.1 §3.2 |
|
||||
| **210757** | SVG 含不安全内容 | 含 `<script>` / `<foreignObject>` / `on*` 事件 / `javascript:` 外链 | §3.1 §3.2 |
|
||||
|
||||
> `parse-svg-text` 的错误码是文件路径 `parse-svg` 的子集(无 `210753`「文件为空」/`210756`「文件读取失败」——这两个仅文件上传场景有;字符串为空由 `@NotBlank` 在网关层返 400)。错误码段位 210700-210799 归属图标库模块。
|
||||
|
||||
---
|
||||
|
||||
## 7. 验证(测试服实测,已通过)
|
||||
|
||||
| 用例 | 输入 | 结果 |
|
||||
|---|---|---|
|
||||
| 合法字符串 | 标准 SVG | http200 / code200,`svgContent` 回显、`fileName=null`、`size=56` |
|
||||
| 含 `<script>` | 带脚本的 SVG | http200 / **code210757** 拒 |
|
||||
| 空白串 | `" "` | http200 / **code400** SVG内容不能为空 |
|
||||
| 中文 SVG | 含 `<title>晴天</title>` | http200 / code200,`size=83` > 字符数 79(证明按 UTF-8 字节计) |
|
||||
|
||||
- 单测 `IconItemServiceTest` 36 全绿(含 script/事件/外链/foreignObject/超限/UTF-8 字节数等正反路径)
|
||||
- hl-user-service 双实例(8081 + 8181)均已部署新代码、health UP
|
||||
|
||||
---
|
||||
|
||||
## 8. 影响评估
|
||||
|
||||
- **是否破坏向后兼容**:否(纯新增端点,无任何已有接口改动)
|
||||
- **前端是否必须同步上线**:是(新输入路径,前端按 §4 接入「第三方库选取」)
|
||||
- **影响已有数据**:无
|
||||
|
||||
---
|
||||
|
||||
## 9. 关联 / 联系人
|
||||
|
||||
- **本次 PR**:#3437(Closes #3434)
|
||||
- **图标库模块首推 changelog**:`03_3390_图标库模块-新增接口-管理后台+小程序.md`(含分类/图标/上传解析全量契约)
|
||||
- **后端负责人**:@wx
|
||||
- **前端对接(管理后台)**:mmg
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户