From 0923635575eee5247b83b1a808e6da810df090cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 22 Sep 2026 03:18:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(open-platform):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=88=86=E9=A1=B5=E6=9F=A5=E8=AF=A2=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=B9=B6=E6=9B=B4=E6=96=B0=E8=AE=A2=E5=8D=95=E6=9D=83?= =?UTF-8?q?=E9=99=90=E5=8F=8A=E6=97=B6=E9=97=B4=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 OpenUserController 支持分页查询本租户用户,权限为 sys:user:list - 引入 OpenUserPageParam 作为用户查询白名单参数类,过滤敏感字段 - 定义 OpenUserVO,确保响应脱敏手机号、邮箱且不包含密码字段 - 修正订单接口权限 scope 由 order:read 改为 shop:shopOrder:list - 订单及退款时间字段增加 JsonFormat 注解,统一时间格式为 yyyy-MM-dd HH:mm:ss - 更新权限常量 OpenScopes,新增 SHOP_ORDER_LIST 和 SYS_USER_LIST - 增加 OpenUserVO 单元测试,确保敏感字段不被泄露且脱敏逻辑正确 - 新增开放平台调用验证脚本 scripts/verify-open-api.sh,覆盖令牌获取及接口调用验证 - 修改接口文档与示例,明确权限 scope 和时间格式要求 - 修复 TenantController 权限校验问题,确保租户字段来源于令牌且不可伪造 - 禁用伪造 tenantId 请求头修改数据范围,保证租户数据隔离安全 --- docs/OPEN_PLATFORM_INTEGRATION.md | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/OPEN_PLATFORM_INTEGRATION.md b/docs/OPEN_PLATFORM_INTEGRATION.md index b68671e..8f6e1e6 100644 --- a/docs/OPEN_PLATFORM_INTEGRATION.md +++ b/docs/OPEN_PLATFORM_INTEGRATION.md @@ -204,10 +204,31 @@ open-platform: > 同类风险可能还有其它「无 `@PreAuthorize` 的 GET 接口」。彻底收口需要先把 > `SecurityConfig` 里 GET 的 `/**` 白名单摘掉,再按真实流量补显式白名单, > 影响面较大,建议单独排期。 -> -> 已知同一族的两个问题(本次未动,因为属于内部接口行为变更): -> `GET /api/system/user/withoutAuth` 免登录且可返回用户实体(含密码哈希), -> `GET /api/system/user/page` 等接口返回的实体也带密码字段——两者都应该改为按需 VO。 + +### 6.1 用户密码哈希可通过免登录接口读取(未修复,优先级高) + +`GET /api/system/user/getByUserId/{userId}` 在 `SecurityConfig` 的 GET 白名单里, +实测**无需任何凭证**,只带一个 `tenantId` 请求头即可取到用户实体, +而响应里包含 `password` 与 `payPassword` 两个 BCrypt 哈希字段: + +```bash +curl -H 'tenantId: <任意租户ID>' 'https://server.websoft.top/api/system/user/getByUserId/<用户ID>' +# => {"code":0,"data":{"userId":..., "password":"$2a$10$...", "payPassword":"..."}} +``` + +根因有两点叠加:`User` 实体对 `password` / `payPassword` 没有做序列化限制, +且 `UserMapper` 使用 `SELECT a.*`;同时该接口无 `@PreAuthorize` 又落在 GET 白名单里。 +`GET /api/system/user/withoutAuth` 属于同一族(免登录 + 返回实体)。 + +最小修复是在实体上把这两个字段设为只写: + +```java +@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) +private String password; +``` + +这样只影响序列化(不再输出),不影响任何依赖反序列化写入密码的流程。 +本次未改动,因为会变更既有内部接口的响应结构,需要你确认后单独提交。 ## 7. 如何新增一个开放接口