ether
|
8ce666d7df
|
fix(security): ce-code-review P0 修复 - 内部 API 白名单 + Feign 事务边界
Backend CI / Build & Test (push) Waiting to run
Details
P0 A1: HeaderAuthenticationFilter 阻断 Feign 内部调用导致 U3 登录审计静默失效
- 将 /api/internal/** 加入 HeaderAuthenticationFilter 和 SecurityConfig 白名单
- InternalApiInterceptor 通过 X-Internal-Token 独立鉴权,无需 X-From-Gateway
- 修复前: pms-auth Feign 调用 /api/internal/login-logs 被 403 阻断, t_login_log 表空置
- 修复后: 内部 Feign 调用放行, 由 InternalApiInterceptor 校验 X-Internal-Token
P0 C9+R1: @Transactional login() 内 Feign 调用持有 DB 连接导致连接池耗尽风险
- 使用 TransactionSynchronizationManager 将 Feign 调用延迟到 afterCompletion 执行
- afterCompletion 在 commit/rollback 后均触发, 确保 SUCCESS 和 FAIL 日志都能记录
- 修复前: Feign 超时 3s 期间 DB 连接被持有, 高并发登录可耗尽 HikariCP 连接池
- 修复后: DB 连接在事务完成后释放, Feign 调用在事务外执行
验证:
- :pms-common:compileJava :pms-auth:compileJava 编译通过
- HeaderAuthenticationFilterTest 5 个测试全部通过
- AuthServiceTest/AuthServiceImplLoginLogTest/PlatformLoginServiceTest 22 个测试全部通过
|
2026-07-05 23:53:03 +08:00 |
ether
|
ad78adf84c
|
fix(security): ce-code-review P0 修复 - 内部 API 白名单 + Feign 事务边界
P0 A1: HeaderAuthenticationFilter 阻断 Feign 内部调用导致 U3 登录审计静默失效
- 将 /api/internal/** 加入 HeaderAuthenticationFilter 和 SecurityConfig 白名单
- InternalApiInterceptor 通过 X-Internal-Token 独立鉴权,无需 X-From-Gateway
- 修复前: pms-auth Feign 调用 /api/internal/login-logs 被 403 阻断, t_login_log 表空置
- 修复后: 内部 Feign 调用放行, 由 InternalApiInterceptor 校验 X-Internal-Token
P0 C9+R1: @Transactional login() 内 Feign 调用持有 DB 连接导致连接池耗尽风险
- 使用 TransactionSynchronizationManager 将 Feign 调用延迟到 afterCompletion 执行
- afterCompletion 在 commit/rollback 后均触发, 确保 SUCCESS 和 FAIL 日志都能记录
- 修复前: Feign 超时 3s 期间 DB 连接被持有, 高并发登录可耗尽 HikariCP 连接池
- 修复后: DB 连接在事务完成后释放, Feign 调用在事务外执行
验证:
- :pms-common:compileJava :pms-auth:compileJava 编译通过
- HeaderAuthenticationFilterTest 5 个测试全部通过
- AuthServiceTest/AuthServiceImplLoginLogTest/PlatformLoginServiceTest 22 个测试全部通过
|
2026-07-05 23:48:30 +08:00 |
ether
|
e2cd391d71
|
U8: 复测总览 + Redisson 决策归档
全量复测通过:
- ./gradlew compileJava: 全量编译通过(0 errors)
- ./gradlew test: 全量测试通过(114+ tests, 0 failures)
Redisson 决策归档:不引入
依据:现有 setIfAbsent 覆盖幂等+简单锁场景,无强烈竞争需求,与 lazy 原则一致。
重新评估触发条件:分布式锁竞争热点 / 分布式数据结构需求。
在 P1 计划文档追加执行结果表(U1-U8 commit hash + 复测状态)和 Redisson 决策归档。
|
2026-07-04 23:50:55 +08:00 |
ether
|
ed6a929b90
|
U7: @Idempotent 落地 payment:pay 场景(防重复支付)
@Idempotent 注解和 IdempotentAspect 此前已建未用(Redis+DB 双保障幂等机制)。
lazy 决策:落地 1 个最典型场景比清理(涉及迁移脚本风险)更省。
在 PaymentController.pay 端点添加 @Idempotent(operation = "payment:pay", expireHours = 24):
- 客户端通过 Idempotency-Key 请求头传入幂等键
- 首次请求正常处理,响应缓存到 Redis + DB
- 重复请求(相同键)返回首次缓存结果
- 业务失败时删除 Redis 占位符允许重试
- 不传键则跳过幂等校验(向后兼容)
编译通过:./gradlew :pms-charge:compileJava
|
2026-07-04 23:47:49 +08:00 |
ether
|
69d0be54c1
|
U6: pms-auth controller @AuditLog + @PreAuthorize 补齐
补齐 pms-auth 4 个控制器的权限与审计注解缺口:
- OrgController: 3 个 GET 端点(list/tree/treeByParent)补加 @PreAuthorize('system:org:manage')
对齐 pms-base 模式:所有端点(读+写)都加 @PreAuthorize,防止未授权数据访问
- AuthController: /password/reset(管理员重置密码)补加 @PreAuthorize('system:user:manage') + @AuditLog(UPDATE, recordParams=false)
recordParams=false 因 ResetPasswordRequest 含密码敏感字段
- RoleController / UserController: 已有完整注解,无需修改
AuthController 其他端点(login/logout/refresh/captcha/userinfo/switch-project/check-permission/password)是认证流程端点,
依赖 SecurityConfig 的 authenticated() 策略,不需要 @PreAuthorize 权限码。
更新 OrgControllerCrudTest$SecurityAnnotationTest.readMethods_noPreAuthorize
→ readMethods_havePreAuthorize:断言读方法现在也有 @PreAuthorize('system:org:manage')。
测试全部通过:./gradlew :pms-auth:test (114 tests)
|
2026-07-04 23:46:15 +08:00 |
ether
|
3bad88d083
|
U5: pms-charge 7 controller @AuditLog + @PreAuthorize 全覆盖
为 pms-charge 服务的 7 个用户态控制器(共 29 个端点)添加权限与审计注解:
- DashboardController: 1 GET → @PreAuthorize('charge:dashboard:manage')
- ChargeStandardController: 6 端点 → @PreAuthorize('charge:standard:manage'),写操作加 @AuditLog(CREATE/UPDATE/DELETE)
- ChargeBillController: 8 端点 → @PreAuthorize('charge:bill:manage'),写操作加 @AuditLog(CREATE/UPDATE/EXPORT)
- InvoiceController: 4 端点 → @PreAuthorize('charge:invoice:manage'),写操作加 @AuditLog(CREATE/UPDATE)
- ReconciliationController: 3 端点 → @PreAuthorize('charge:reconciliation:manage'),写操作加 @AuditLog(CREATE)
- PaymentController: 4 端点(排除 2 回调)→ @PreAuthorize('charge:payment:manage'),/pay 加 recordParams=false(含支付敏感信息)
- RefundController: 3 端点(排除 1 回调)→ @PreAuthorize('charge:refund:manage'),写操作加 @AuditLog(CREATE)
InternalController(/api/internal/charge/*)通过 internal token 鉴权,不加注解。
PaymentController/RefundController 的 /callback/* 端点独立验签,不加注解。
模式对齐 pms-base:所有端点(读+写)都加 @PreAuthorize,写操作额外加 @AuditLog,敏感操作加 recordParams=false。
编译通过:./gradlew :pms-charge:compileJava
|
2026-07-04 23:42:30 +08:00 |
ether
|
bdc0f717fb
|
fix(security): U4 修复 2 处 Feign 降级日志未脱敏手机号
全局扫描 pms-charge/operation/base/file/gateway/audit 6 个服务的日志语句,
发现 2 处 getPhone() 未包裹 SensitiveDataUtils.maskPhone:
- pms-charge/feign/NotifyClient.java:58 — sendSms 降级日志
- pms-operation/feign/NotifyClient.java:73 — sendSms 降级日志
两处均为 Feign fallback 工厂中 notify-service 不可用时的静默降级日志,
打印 SmsRequest.phone 明文,存在日志泄露风险。
修复:包裹 SensitiveDataUtils.maskPhone(request.getPhone()),与 U2/P0 脱敏策略一致。
扫描覆盖范围:
- phone/mobile/idCard/idNo/email/password/secret/privateKey/apiKey/token 关键字
- getPhone()/getIdCard()/getEmail()/getPassword() 直接调用
- 结果:除上述 2 处外无其他敏感字段明文日志(pms-operation/SubinClient 的 token 为幂等标识非认证 token)
验证:./gradlew :pms-charge:compileJava :pms-operation:compileJava 通过
|
2026-07-04 23:34:19 +08:00 |
ether
|
fdec682f00
|
refactor(config): U3 7 服务 application 配置按环境拆分
复用 pms-auth 模板(commit b28a5fb),对 7 个服务进行相同的配置拆分:
- pms-audit / pms-base / pms-charge / pms-file / pms-notify / pms-operation / pms-gateway
每个服务的 application.yml 改动:
1. profiles.active: dev -> ${SPRING_PROFILES_ACTIVE:dev}(参数化,支持环境变量切换)
2. 移除 logging.level.com.pms: debug(迁移至 dev/prod profile)
3. 移除 internal.api.token 的 dev 默认值(迁移至 dev/prod profile,prod 无默认值 fail-fast)
4. 保留 internal.api.enforce: ${INTERNAL_API_ENFORCE:true}(已参数化,留在公共配置)
新增 application-dev.yml:com.pms: debug + internal.api.token dev 默认值
新增 application-prod.yml:com.pms: info + internal.api.token 无默认值(fail-fast)+ enforce: true
pms-gateway 特殊处理:dev/prod 仅含 logging(无 internal.api 配置),
common 保留 org.springframework.cloud.gateway: info 日志行。
行为等价:默认 SPRING_PROFILES_ACTIVE=dev 时与改动前完全一致。
安全收益:prod 环境无法误用 dev token,日志级别由 profile 隔离。
验证:python3 yaml.safe_load_all 校验 24 个 YAML 文件全部语法正确
|
2026-07-04 23:32:44 +08:00 |
ether
|
388e22f1eb
|
refactor(notify): U2 统一手机号脱敏至 SensitiveDataUtils.maskPhone
清理 pms-notify 模块 3 处重复的私有 desensitizePhone 方法:
- SmsServiceImpl: 4 处调用(含入库前脱敏安全设计)+ 私有方法
- AliyunSmsProvider: 3 处调用 + 私有方法
- TencentSmsProvider: 3 处调用 + 私有方法
3 个私有方法逻辑与 pms-common SensitiveDataUtils.maskPhone 完全一致
(前 3 后 4,长度<7 原样返回),统一调用工具类消除重复。
行为保持:SmsRecord.phone 入库前脱敏的安全设计不变,仅替换调用入口。
验证:./gradlew :pms-notify:test 全部通过
|
2026-07-04 23:27:14 +08:00 |
ether
|
f5d4a068fd
|
fix(U1,P1): 清理 MapStruct 未使用依赖 + 修复遗留测试缺陷
- 移除 8 个服务 build.gradle 的 MapStruct 依赖与注解处理器
- 移除根 build.gradle 的 MapStruct dependency management 与 annotationProcessor
- 移除 gradle.properties 的 mapstructVersion 与 lombokMapstructBindingVersion
- 修复 P0 遗留:GatewayAuthorizationManagerTest 补 orgId 参数(GatewayPrincipal 第 10 字段)
- 修复预先存在缺陷:AbilityPackageServiceTest 补 abilityPackageVersionMapper mock(NPE)
- 新增 P1 修复计划文档 docs/plans/2026-07-04-003-fix-foundation-p1-engineering-plan.md
- 复测:./gradlew test 全量通过
|
2026-07-04 23:22:20 +08:00 |
ether
|
596494f7d6
|
fix(U5): 移除 4 个 PlatformProvider 的全响应 debug 日志——避免敏感信息泄露
- WechatPlatformProvider: 移除 code2session/getuserphonenumber 响应日志(含 session_key/phoneNumber)
- AlipayPlatformProvider: 移除 oauth.token 响应日志(含 access_token)
- DingtalkPlatformProvider: 移除 getuserinfo_bycode 响应日志(含 mobile)
- QywechatPlatformProvider: 移除 getuserdetailuserinfo 响应日志(含 mobile)
- 错误场景仍由 log.warn(errcode/errmsg) 覆盖,不影响排障
|
2026-07-04 22:56:57 +08:00 |
ether
|
b28a5fbde4
|
fix(U4): pms-auth application-{env}.yml 环境拆分——dev/prod profile 隔离
- application.yml 保留公共配置,profiles.active 改为 env var 控制
- application-dev.yml: debug 日志 + captcha.debug=true + token 有 dev 默认值
- application-prod.yml: info 日志 + captcha.debug=false + INTERNAL_API_TOKEN 无默认值(fail-fast)
- application-prod.yml 仅含占位符无明文密钥,force-add 绕过 .gitignore
- 模板可复用于其他 7 个服务
|
2026-07-04 22:53:48 +08:00 |
ether
|
14d61346e4
|
fix(U3): pms-auth Feign 接入登录日志——login/logout/fail 全路径审计
- AuditFeignClient + Feign DTO,POST /api/internal/login-logs
- AuthServiceImpl 注入 ObjectProvider<AuditFeignClient>(容错)
- login 成功记 SUCCESS,失败记 FAIL;logout 记 LOGOUT
- recordLoginLog: try-catch 兜底,失败仅 log.warn 不阻断主流程
- loginByPlatform 手机号日志改用 SensitiveDataUtils.maskPhone
- 7 个单测覆盖 success/fail/logout/Feign 异常/未注入场景
|
2026-07-04 22:51:33 +08:00 |
ether
|
0b86e06dff
|
fix(U5): SensitiveDataUtils 全局脱敏工具类——U3 依赖前置
- maskPhone/maskIdCard/maskEmail 统一规则
- null/空串/长度不足原样返回
- 16 个单测覆盖边界值
|
2026-07-04 22:45:55 +08:00 |
ether
|
365fd51fb2
|
fix(U2): pms-audit 登录日志写入端点——LoginLogService.create + InternalLoginLogController
P0-3 part 1: pms-audit 原有只读查询 API,无写入端点。
- CreateLoginLogRequest DTO(userId 可空,兼容登录失败)
- LoginLogService 增加 create 方法
- LoginLogServiceImpl 实现 create(logNo 生成、userAgent 解析)
- InternalLoginLogController POST /api/internal/login-logs
(InternalApiInterceptor 校验 X-Internal-Token)
复测:LoginLogServiceImplTest 3 个 create 场景全部通过。
|
2026-07-04 22:39:43 +08:00 |
ether
|
6273ab14f3
|
fix(U1): orgId 链路修复——补全 JWT→网关→下游 UserContext→DataScope 传递
P0-2: orgId 已在 JWT claims 签发但下游链路断裂,导致 data_scope=2/3
沉默降级为本人过滤。补全 4 个环节:
- HeaderConstants 加 ORG_ID 常量
- GatewayPrincipal record 加 orgId 字段
- HeaderInjector 注入 X-Org-Id header
- HeaderAuthenticationFilter 读取 X-Org-Id 传入 CurrentUser(原硬编码 null)
复测:HeaderAuthenticationFilterTest 验证 orgId 正确传入;
DataScopeInterceptorTest 验证 data_scope=2 条件含 org_id(已有)。
同时包含 P0-1 RoleController @PreAuthorize + @AuditLog 修复。
|
2026-07-04 22:37:20 +08:00 |