fix:图片访问

fix:权限修改
This commit is contained in:
dzc committed 2026-10-29 14:28:38 +08:00
1 parent 710e4cfb90
commit bbde6cc87f
56 files changed
+2671 -271

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
# 文件访问签名接入与发布
本次保护 `/admin/sys-file/oss/file` 的全部文件。默认 `observe` 只记录签名校验结果;只有加载完整配置并切到 `enforce` 后,普通裸链接才会被拒绝。旧 Dart 图片兼容是独立开关。客户端密钥可提取、UA 可伪造、有效接口地址仍可被模拟请求使用,这是一层应用级校验,不是用户或租户文件授权。
## 配置准备
服务端配置见 `config.example.yml`。密钥为至少 32 字节随机数据的 Base64 字符串,HMAC 使用 **Base64 解码后的字节**。不要复用 OAuth 客户端信息或密码加密密钥。
在 `pj_service_cloud` 执行以下命令可为并列的五个项目生成匹配的本地配置:
```bash
python3 scripts/generate-file-access-config.py \
--public-base-url https://www.pjzhhq.cn/api \
--allowed-origin https://stgl.pj.gov.cn
```
按用户最终要求,所有环境共用一套密钥配置,`admin/h5/mini/flutter/service/package` 各自保留固定密钥;开发、测试、生产不再另建密钥组。只有公网基础地址等部署参数随目标环境填写。脚本统一读取 `.file-access/keys.json`,重复执行不会更换密钥;旧命令的 `--environment` 参数仍接受,但不再切换密钥。
迁移时沿用原生产密钥组,避免已构建客户端失效。脚本只更新受管理的文件访问配置字段,保留其他业务环境变量;移除旧 Vite 模式文件中的文件访问字段,避免其覆盖公共配置。旧文件备份位于 Java 项目的 `.file-access/migration-backup/`,不参与构建。当前活动配置均被 Git 忽略:
首次生成只做一次,其他构建机器和 CI 同步这套现有配置。密钥统一后无需随部署环境重新生成。
| 项目 | 本地文件 | 使用方式 |
| --- | --- | --- |
| Java | `.file-access/config.yml` | Nacos 共享配置或 Spring 外部配置 |
| 后台 | `.env.local` | 所有 Vite 构建模式共用 |
| H5 和小程序 | 各项目的 `.env.local` | 所有 Vite 构建模式共用 |
| Flutter | `.file-access/config.json` | 所有构建使用 `--dart-define-from-file=.file-access/config.json` |
前端的配置项为 `VITE_FILE_ACCESS_APP_ID`、`VITE_FILE_ACCESS_KEY_ID`、`VITE_FILE_ACCESS_KEY`、`VITE_FILE_ACCESS_ALLOWED_ORIGINS`。Flutter 去掉 `VITE_` 前缀。Java 的 `clients` 包含 `admin/h5/mini/flutter/service/package`;`service` 和 `package` 密钥只放服务端。
`public-base-url` 是外部可访问的网关基础地址,可以带 `/api`,不含 `/admin/sys-file/oss/file`。现有的图片/API 基础地址继续由各端原有配置决定;`allowed-origins` / `ALLOWED_ORIGINS` 只列确实属于本系统的历史域名。上线前必须逐环境核对域名、基础路径、appId、kid 和密钥。相对 `/api/admin/sys-file/oss/file` 按当前文件基础地址解析,绝对历史地址保留其原有域名和部署路径。
**Java 不会自动读取仓库里的 `.file-access`。** 本地运行可以设置:
```bash
export SPRING_CONFIG_ADDITIONAL_LOCATION=file:/absolute/path/pj_service_cloud/.file-access/config.yml
```
通过现有 Nacos 配置体系加载这套 `file-access` 配置,或把外部配置挂载到各服务并设置上述变量。实际部署路径与公网基础地址应对应目标机器。首次生成默认为 `observe`,已有配置保留当前模式;显式 `--mode` 可更新本地生成配置的模式。先检查配置源优先级;`config.example.yml` 中的环境变量占位符不能代替实际密钥。严格模式缺少任一客户端的有效活动密钥或公网基础地址会启动失败;运行中错误配置会返回 500,不会降级匿名访问。即使在观察模式,版本签发和服务间读取也需要配置 `package/service` 密钥。
## 协议
请求查询参数为 `appId`、`kid`、`ts`、`sign`、`fileName`。签名原文按 LF 连接,无末尾换行:
```text
v1
oss-file-read
appId
kid
ts
Base64URL无填充编码的UTF-8文件名
```
`ts` 是 Unix 秒;`sign` 是 HMAC-SHA256 的 64 位小写十六进制。`fileName` 只 URL 解码一次,始终放在最后。后端生成的 APK URL 因此仍以 `.apk` 结尾,兼容旧终端的扩展名解析。
默认普通签名有效 1800 秒,`package` 有效 86400 秒,允许签发时间领先最多 300 秒。`GET /admin/sys-file/oss/access-info` 匿名返回 `R.data.serverTime`(**毫秒**)和 `ttlSeconds`,不包含密钥。各端校准时差并在签名剩余不足 5 分钟时续期;校时失败保留上次时差,不能退回裸链接。传输 URL 缓存在内存里,普通渲染不会每次产生新签名。
重复关键参数、缺少字段、非规范时间戳或非规范签名为 400;未知客户端/密钥、错误签名、过期、时钟越界为 403;文件不存在为 404,数据库或存储读取失败为 500。GET 和 HEAD 共用校验。普通登录 Token 不会绕过校验。文件响应最多私有缓存 5 分钟且不超过剩余签名寿命;错误响应禁止缓存。已经输出部分字节后的网络/存储中断无法可靠改写 HTTP 状态,应按中断响应处理。
`block-browser-navigation` 默认为 `true`。严格模式下,浏览器携带 `Sec-Fetch-Mode: navigate` 或 `Sec-Fetch-Dest: document/iframe/frame` 的文件请求返回 403,即使签名正确也不放行;覆盖地址栏粘贴、新窗口打开和直接嵌入文件页面。图片、音视频以及 fetch/XHR 下载继续校验签名后访问。响应的 `Vary` 包含 `Sec-Fetch-Mode` 和 `Sec-Fetch-Dest`,防止浏览器把图片缓存复用为文件页面。观察模式仅记录 `browser_navigation`,不拦截。
后台会截获本系统文件 `<a>` 链接,通过已有 Blob 下载工具处理;H5/小程序富文本文件链接改走图片预览或下载后打开本地文件。复制出来的接口地址不再承诺可直接在浏览器打开。Flutter 原生下载、Feign 等没有浏览器 Fetch Metadata 的请求仍执行签名/旧 Dart 规则;不支持这些请求头的旧浏览器同样不能靠本规则识别。这项规则用于限制普通浏览器导航,不能防止脚本携带有效签名并模拟请求,也不能阻止已经获准显示的图片被保存。
## 入口与数据约束
| 部分 | 接入位置与行为 |
| --- | --- |
| Java 文件入口 | `FileAccessGuard`,`SysFileController`,`SysFileServiceImpl`;租户跳过只作用于文件查询并恢复原状态 |
| Java 内部读取 | `RemoteFileService` 保留 `getFile` 调用,通过编码桥接和专属 Feign 拦截器签名,保留文件名中的字面 `%xx`;钱包、硬件导出/日志/取证通过相同签名读取;票据 URLConnection 单独适配 |
| APK | 终端 `/app-version/ad/page` 和 `/app/last-version` 返回对象使用 `package` 签名,后台列表/编辑和数据库仍为原始值;独立静态 APK 地址保持不变 |
| 后台 | `src/utils/file-access*.ts`;`FileImage` 保留已加载画面,未加载的懒图片继续续期,打开/切换预览时取有效签名;失败重试仅刷新当前文件,不清空全局签名缓存;上传回显、素材库、头像、视频、版本复制和下载均已接入;KKFileView 在编码之前签名源地址 |
| 后台编辑器 | 只更新编辑器 DOM 的资源属性,不替换整篇文档;输出 HTML 剥离临时签名,续期不进入编辑历史 |
| H5 和小程序 | `src/sheep/utils/file-access*.ts`、`filePath/parseHtml`、共享预览下载工具及各页面资源属性;公共算法不依赖 DOM/window;富文本图片样式保留 |
| Flutter | `FileAccess`、`AppNetworkTool`、`SignedNetworkImage`;主副屏独立初始化,缓存键用规范化原始地址,传输 URL 用签名 |
| Flutter APK 重试 | 原生下载收到 403 时重新查询相同 ID、版本码、平台和应用的已发布版本,最多重试一次,不能换成另一个版本继续安装 |
业务对象、表单、上传返回值、SQLite 人脸 `imagePath`、失败记录和 `referenceImageUrl` 继续保留原始引用。本次没有数据库迁移、SQLite 升级或清空人脸库。新业务展示统一调用文件工具,不要在 API 响应拦截器里递归改写业务字符串。
第三方 URL、静态资源、`data:`、`blob:`、本地临时文件不加本协议签名。复制访问链接是临时访问地址;编辑、存储文件引用使用原始值。
旧终端兼容只接受完整 `Dart/<版本> (dart:io)` UA,且扩展名在 jpg/jpeg/png/gif/webp/bmp/svg/ico 内。完全没有签名参数才可走兼容分支;错误或过期签名不会回退。APK、日志、文档不凭 Dart UA 放行。
## 发布和回滚
1. 在配置中心准备匹配的环境配置,保持 `mode: observe` 和 `legacy-dart.enabled: true`。发布 UPMS、integrated,以及包含文件调用的 wallet、hardware、canteen 等服务和统一公共依赖。只更新 UPMS 会遗漏内部读取。
2. 发布后台、H5、小程序,并提供携带生产配置的新 Flutter 包。小程序保留原文件域名,真机检查 request/downloadFile 域名配置、图片预览和打开文档。
3. 至少观察一个完整业务日,确认登录前 Logo/背景、人员照片、商品/菜品、富文本、附件下载、导出、票据和旧设备更新链路。旧设备必须实测图片 UA 和 Android 原生 APK 下载。
4. 通过验收后设置 `mode: enforce`。按当前配置中心机制刷新或重启实例,逐个确认配置已生效;旧网页需刷新,小程序需加载新版本。
5. 根据设备版本台账确认覆盖后再关 `legacy-dart.enabled`。没有自动失效日,短期没有旧请求不能证明设备已全部升级。
6. 遗漏影响业务时切回 `observe` 并保留诊断;这会重新允许普通未签名请求。无需数据库回滚,也无需四端同时回退。
代理/CDN 必须把文件路径送到后端校验,保留完整查询参数,不得忽略查询参数缓存文件、强制公共缓存或通过其他公开存储入口绕过该接口。校时接口也必须匿名可达。不要在访问日志中记录完整签名 URL、密钥或登录 Token;可按路径、来源类别和结果计数。
监控 `file.access.requests`(Prometheus 通常呈现为 `file_access_requests_total`),标签 `outcome/app/mode`。结果包括 `signed`、`missing_signature`、`malformed_signature`、`invalid_signature`、`expired`、`clock_skew`、`legacy_dart`、`unknown_client`、`unknown_key`、`configuration_error` 等。文件查询/存储失败另计 `file.access.read.failures`。拒绝/兼容日志按结果采样,计数器保留完整次数。
轮换时先在服务端增加新 kid,同时保留旧 kid,再更新客户端构建;服务端主动签发使用 active-kid。Flutter 的旧 kid 需等设备覆盖后才移除。不要用重新运行生成脚本代替轮换流程。
## 本地验证命令
三个前端分别执行:
```bash
node --test tests/file-access.test.cjs
```
后台执行 `pnpm build:prod`,H5 执行 `pnpm build:h5`,小程序执行 `pnpm build:mp-weixin`。跨语言固定向量在各项目 `test-vectors/file-access.json`,其中的密钥是公开测试数据,不能用于部署。
Java 定向回归:
```bash
mvn -pl pjcloud-upms/pjcloud-upms-biz,pjcloud-integrated/pjcloud-integrated-biz,pjcloud-wallet/pjcloud-wallet-biz,pjcloud-hardware/pjcloud-hardware-biz,pjcloud-canteen/pjcloud-canteen-biz \
-am test \
-Dtest=FileAccessTest,FileReadTest,AppVersionFileAccessTest,WalletManageBatchExportTest,WalletLedgerBatchExportTest,HardBatchExportFileTest,HardBatchExportQueryTest \
-Dsurefire.failIfNoSpecifiedTests=false
```
Flutter 使用项目 FVM 3.27.4:
```bash
fvm flutter test --no-pub --dart-define-from-file=.file-access/config.json \
test/file_access_test.dart test/package_download_test.dart \
test/face_sync_plan_test.dart test/face_sync_pipeline_test.dart \
test/face_sync_failure_store_test.dart test/face_readiness_cache_test.dart \
test/customer_display_balance_test.dart test/customer_display_balance_widget_test.dart
fvm flutter build apk --release --no-pub --dart-define-from-file=.file-access/config.json
```
验收结果与待现场验证项见 `verification.md`。不要把本地构建成功或源码中的 Dart UA 推断视为旧安装包验收。
+32
View File
@@ -0,0 +1,32 @@
# Load through Nacos shared config or Spring additional-location. No usable keys are committed.
file-access:
mode: observe
block-browser-navigation: true
ttl-seconds: 1800
package-ttl-seconds: 86400
future-skew-seconds: 300
public-base-url: https://files.example.com/api
allowed-origins:
- https://legacy-files.example.com
legacy-dart:
enabled: true
extensions: [jpg, jpeg, png, gif, webp, bmp, svg, ico]
clients:
admin:
active-kid: v1
keys: {v1: '${FILE_ACCESS_ADMIN_V1:}'}
h5:
active-kid: v1
keys: {v1: '${FILE_ACCESS_H5_V1:}'}
mini:
active-kid: v1
keys: {v1: '${FILE_ACCESS_MINI_V1:}'}
flutter:
active-kid: v1
keys: {v1: '${FILE_ACCESS_FLUTTER_V1:}'}
service:
active-kid: v1
keys: {v1: '${FILE_ACCESS_SERVICE_V1:}'}
package:
active-kid: v1
keys: {v1: '${FILE_ACCESS_PACKAGE_V1:}'}
+94
View File
@@ -0,0 +1,94 @@
# 五端文件签名验证记录
验证日期:2026-10-29。范围为本地五个项目的实现、定向回归、构建和已登录后台页面检查。未发布服务、修改 Nacos、开启生产拦截、更新真实设备、执行数据库迁移或提交 Git。
## 已完成
| 验证 | 结果 |
| --- | --- |
| Java 请求级与业务回归 | 41 项通过,0 失败;覆盖 UPMS 文件校验/读取、版本地址、钱包和硬件导出,同时编译相关公共模块及 canteen |
| 后台自动测试 | 14 项通过,包含文件协议与已有部门导出测试 |
| H5 文件自动测试 | 14 项通过 |
| 小程序文件自动测试 | 14 项通过 |
| 跨语言协议 | Java、三端 TypeScript、Dart 使用相同公开向量;校验 UTF-8 文件名、秒级时间戳、Base64URL 原文和 HMAC 结果 |
| URL 与运行时 | 覆盖中文、空格、加号、百分号编码、历史域名、相对/绝对地址、已有 `/api` 前缀、重复签名、第三方地址;前端测试执行实际运行时包装器,H5/小程序测试执行富文本预览组件的 JS 方法;Java 使用真实 SpringMvcContract/Feign 客户端与内存传输验证文件名字面 `%2F/%2B`、重复拦截和参数顺序 |
| 后台生产构建 | `pnpm build:prod` 通过 |
| H5 构建 | `pnpm build:h5` 通过 |
| 微信小程序构建 | `pnpm build:mp-weixin` 通过 |
| Flutter 定向回归 | 56 项通过;含签名、安装包一次重试、人脸同步计划/流水线/失败记录/缓存、主副屏余额回归 |
| Android Release | FVM Flutter 3.27.4 构建通过,使用 `.file-access/production.json`;APK 约 101.9 MB |
| 新增后台 TypeScript 工具 | 独立严格类型检查通过 |
| 配置生成器 | 在临时目录重复运行,确认幂等、保留已有文件;开发/测试/生产配置和各客户端密钥相互独立 |
| 密钥与原有变更 | 扫描五个项目全部已跟踪及未忽略候选文件,未发现生成密钥泄漏;后台原有补丁可反向校验,Java 原有补丁除追加忽略规则产生的上下文差异外可反向校验 |
| Diff 检查 | 保留原有 CRLF 文件格式;使用 `git -c core.whitespace=cr-at-eol diff --check` 通过 |
APK 位置(相对本仓库):`../pj_supermarket_cloud/build/app/outputs/flutter-apk/app-release.apk`。本次构建尚未在真实终端安装验证;发布前须核对包内环境与服务端配置一致。
Java 定向测试及各端构建命令见 [接入与发布说明](README.md)。本机详细日志保存在 `/tmp/pj-file-access-work/`,属于临时验证资料,不随仓库发布。
## 静态检查与既有问题
使用任务开始前保存的补丁还原临时代码基线,与当前代码运行同一检查后比较:
| 项目 | 当前结果与基线比较 |
| --- | --- |
| 后台 `vue-tsc` | 6 条既有解析错误,均在 `src/views/admin/system/tenant/index.vue:83`;与基线完全一致 |
| H5 `vue-tsc` | 4 条既有解析错误,在 `src/pages/tabbar/~individualOrder.vue:78-79`;与基线完全一致 |
| 小程序 `vue-tsc` | 17 条既有 TS6504(JS Vue 来源与 allowJs 配置);规范化临时目录路径后与基线完全一致 |
| Flutter `analyze --no-pub` | 69 条提示/警告;忽略因新增代码产生的行号偏移后,诊断集合与基线完全一致,无新增项 |
因此不能把本次结果表述为“全项目类型检查通过”。H5/小程序构建仍有 TM UI 类型导出和循环依赖等构建提示;构建已成功,未在本次跨端文件改造中整理无关依赖。
## 已登录后台检查
使用用户提供的 `http://localhost:8888/` 已登录会话,检查文件管理页:
- 本系统有效图片的缩略图与放大预览加载成功,资源请求带 `appId/kid/ts/sign`,`fileName` 位于最后。
- 实测发现并修复前端 `/api` 前缀被重复保留的问题:当前开发图片服务器不带 `/api`,相对旧路径应转换为 `/admin/sys-file/oss/file`。配置含 `/api` 的部署仍保留一次前缀。
- 旧头像的一条原始文件链接返回 HTTP 200、内容长度为 0,属于当前运行后端/存储的既有异常。新 Java 读取代码已覆盖不存在和存储异常状态,但尚未发布,不能声称现场问题已修复。
- 当前后端匿名 `/admin/sys-file/oss/access-info` 返回 424 鉴权错误,说明运行环境尚未具备本次匿名校时接口;签名客户端会保留本地时间/最近偏移,不降级匿名读取。
- 点击素材下载后未出现页面错误,但浏览器下载事件未在等待窗口内返回。浏览器工具自动安全检查拒绝打开 `chrome://downloads/`(仅允许 HTTP/HTTPS),未采用其他方式绕过此限制,**下载文件实际落盘未确认**。
当前运行后端仍接受裸文件链接。上述浏览器结果证明前端签名与展示链路可用,不代表新后端严格校验已在线生效。
## 发布前仍需完成
1. 核对每个环境的公网基础地址、历史域名、密钥和活动 kid;Java 不会自动加载 `.file-access/*.yml`,须通过 Nacos 或 `SPRING_CONFIG_ADDITIONAL_LOCATION` 加载。先以 `observe` 发布 UPMS、integrated 和所有实际调用文件服务的模块。
2. 用发布后的后端确认匿名校时可达,执行 GET/HEAD、错误参数、错误/过期签名、旧 Dart 兼容、404/500、私有缓存及服务间读取联调。
3. 在真实旧 Flutter 安装包上确认图片请求 UA、图片显示及 Android 原生 APK 下载。新版包确认主副屏、缓存命中、人脸重复同步/离线恢复、取证、打印、手动/自动更新;不能用本地源码或单元测试替代设备验收。
4. 微信真机验证登录前 Logo/背景、长时间停留和恢复前台、图片预览、文件下载及打开文档;核对微信文件域名配置。后台与 H5 补充对应实际业务操作验收。
5. 至少观察一个完整业务日,确认已知入口无遗漏后再切 `enforce`;根据设备版本台账确认升级覆盖后再关闭旧 Dart 图片兼容。
当前默认保持 `observe` 与旧 Dart 图片兼容开启。回滚方法是恢复 `observe` 并保留诊断日志;业务引用和人脸记录未持久化临时签名,无需数据库回滚。
## 后台图片闪烁修复补充
2026-10-29 修复后台单张图片失败重试清空全局签名缓存的问题。重试只刷新当前文件,同一文件的并发重试合并;普通校时保留仍有效的签名。新增公共 `FileImage`,已加载图片在分钟检查、签名续期和恢复前台时保持当前画面;未加载的懒图片继续更新有效地址,放大预览在打开或切换图片时取有效签名。业务引用改变时正常加载新图。
- 后台定向回归 19 项通过,包含真实组件 setup、模板与 Vue 生命周期测试;模拟停留超过 30 分钟、恢复前台、失败重试、预览和懒加载。
- 新组件与文件工具的定向 `vue-tsc` 检查通过;后台生产构建通过。
- 已登录商户页实测:原先已加载的 24 张图片跨分钟检查后地址不变,其余慢图片随后加载完成,共 30 张图片成功、无加载占位;放大预览成功且请求带签名。
## 浏览器直接打开文件地址限制补充
2026-10-29 新增默认开启的 `block-browser-navigation`。严格模式下,携带浏览器页面导航 Fetch Metadata 的文件请求,即使签名有效也返回 403;页面图片、音视频、fetch/XHR 下载和无浏览器 Metadata 的原生/服务请求继续按原签名规则处理。成功响应 `Vary` 区分导航与子资源请求;拒绝响应 `no-store`。观察模式仅记录 `browser_navigation`。
- Java 文件访问/读取请求级测试共 12 项通过,覆盖签名正确的导航、GET/HEAD 在读取存储前拒绝、图片与下载放行、原生包下载、Dart UA 不绕过导航限制、开关和观察模式。
- 后台 20 项、H5 16 项、小程序 16 项定向测试通过。覆盖文件链接的页面内下载、H5 富文本与普通链接拦截、图片预览、本地文档打开及第三方链接保持原行为。
- 后台生产、H5、微信小程序构建通过;后台文件组件/工具定向类型检查通过。
- 配置生成器在临时目录验证:新配置含 `block-browser-navigation: true`,默认仍为 `observe`,没有修改实际运行环境配置。
这项补充尚未部署到文件服务器,不能把本地请求级测试表述为该公网地址已返回 403。上线时代理须保留 `Sec-Fetch-Mode/Dest` 和响应 `Vary`;用新签名或无旧缓存的窗口验证。后端无法收回浏览器已经取得的文件内容。旧浏览器可能不提供 Fetch Metadata,脚本也能模拟请求,因此这项规则不等于逐用户授权或防止已显示图片被保存。
## 最终调整:统一一套密钥与严格模式联调
用户明确要求所有环境使用同一套密钥,取代本文前面记录的开发/测试/生产独立密钥方案。沿用已配置的原生产密钥组,未生成新密钥;各 appId 仍使用各自固定密钥,service/package 密钥仍只存在服务端。三个前端统一使用 `.env.local`,Java 使用 `.file-access/config.yml`,Flutter 使用 `.file-access/config.json`。旧模式文件的签名字段已清理并备份,旧命令 `--environment` 不再切换密钥。
此前严格模式白图的真实原因是:浏览器按开发密钥签名,后端配置的是原生产密钥,实际响应为 `invalid_signature`。本次已通过本地 Nacos REST API 修正 `application-dev.yml`,保留 `enforce`、浏览器导航拦截和旧 Dart 兼容,公网基础地址对齐测试网关。Nacos 完整原配置保存在本机私有临时备份,发布时使用 MD5 比较避免覆盖并发编辑,生产服务配置未修改。
- 使用真实页面中的同一个签名 URL 联调:页面图片请求 200、应用下载请求 200、浏览器导航请求 403,原因为 `browser_navigation`。
- 实际后台重新加载后,首轮观察为 30 张图片中的 24 张加载成功,其余 6 张仍在慢请求中;随后浏览器自动化连接中断,未把该轮全部图片的最终状态作为已验证结果。签名已与统一密钥注册表一致。
- 真实 Vite `loadEnv` 验证三个项目共 18 个模式组合,全部使用统一密钥;生成器迁移、重复执行、原密钥保留与错误配置拒绝共 3 项测试通过。
- 后台生产、H5、微信小程序构建通过;Flutter 使用统一配置执行签名和安装包定向测试,8 项通过。
后续构建与配置准备以 README 中的统一路径为准。本文前面提到的分环境配置路径属于历史验证记录,不再作为当前操作指引。