feat(open-platform): 新增用户分页查询接口并更新订单权限及时间格式

- 添加 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 请求头修改数据范围,保证租户数据隔离安全
This commit is contained in:
2026-09-22 03:18:27 +08:00
parent ea5021c3f0
commit 0923635575
+25 -4
View File
@@ -204,10 +204,31 @@ open-platform:
> 同类风险可能还有其它「无 `@PreAuthorize` 的 GET 接口」。彻底收口需要先把 > 同类风险可能还有其它「无 `@PreAuthorize` 的 GET 接口」。彻底收口需要先把
> `SecurityConfig` 里 GET 的 `/**` 白名单摘掉,再按真实流量补显式白名单, > `SecurityConfig` 里 GET 的 `/**` 白名单摘掉,再按真实流量补显式白名单,
> 影响面较大,建议单独排期。 > 影响面较大,建议单独排期。
>
> 已知同一族的两个问题(本次未动,因为属于内部接口行为变更): ### 6.1 用户密码哈希可通过免登录接口读取(未修复,优先级高)
> `GET /api/system/user/withoutAuth` 免登录且可返回用户实体(含密码哈希),
> `GET /api/system/user/page` 等接口返回的实体也带密码字段——两者都应该改为按需 VO。 `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. 如何新增一个开放接口 ## 7. 如何新增一个开放接口