Commit Graph

16 Commits

Author SHA1 Message Date
lzh
cbbb048a4d feat(system): 按 OAuth2 客户端 platform 过滤菜单,支持业务/物联双前端
问题:业务平台(biz)和物联运维平台(iot)共用一套用户体系和菜单表,但每个前端
只该看到自己域的菜单。原来没有按客户端过滤的机制。

方案:在 OAuth2 客户端维度打 platform 标签(biz/iot/NULL),菜单也打同样标签,
登录时下发菜单按二者匹配过滤。

链路:
- OAuth2AccessTokenCheckRespDTO / LoginUser(framework + gateway)新增 clientId 字段
- TokenAuthenticationFilter(framework + gateway)把 accessToken.clientId 带进 LoginUser
- WebFrameworkUtils.HEADER_CLIENT_ID="X-Client-Id":登录/refresh 等"无 token 入口"
  允许前端声明 client,避免硬编码 default
- AdminAuthServiceImpl.resolveClientId:未传 Header 时回退 OAuth2ClientConstants.CLIENT_ID_DEFAULT
- MenuDO / OAuth2ClientDO 各加 platform 列
- MenuService.filterMenusByPlatform:platform 为空(全平台共用)或匹配即保留

SQL 迁移按字母序编号:
- _01_oauth2_client_platform.sql:加列 + 给 default/iot-client 客户端打标 + 递归标
  IoT 菜单子树(root id=4000)为 iot
- _02_bulk_mark_biz_menus.sql:其余 platform=NULL 的菜单兜底标 biz
- 顺序依赖:_01 标完 iot 后 _02 才动剩余 NULL,避免 _02 把 IoT 菜单错标 biz

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 13:32:26 +08:00
lzh
4564eec893 chore(tenant): Tenant RPC Feign 客户端列表引入 ProjectCommonApi
框架层 starter-biz-tenant 的 @EnableFeignClients 补齐 ProjectCommonApi,
供租户隔离检查时跨服务拉取项目元数据使用。后续如体量增长可考虑拆独立
ViewshProjectRpcAutoConfiguration。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 13:31:55 +08:00
lzh
04961ee614 feat(web): API 访问日志支持 exclude-paths 过滤高频心跳刷屏
- 新增 viewsh.access-log.exclude-paths 配置(Ant Pattern),命中路径默认不打 INFO
- 异常或 HTTP 4xx/5xx 时仍打 WARN,保证"默认安静、出错必响"
- ApiAccessLogInterceptor 保留无参构造,兼容老用法
- gateway application.yaml 补注释:ZLM Hook 走 video-server 直连而非网关,理由说明

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 13:31:44 +08:00
lzh
9784d7dd8e perf(system): 项目授权校验改单行查询 + AuthController 切 FromCache
背景:feat/multi-tenant-project 联调发现 /admin-api/** 全线变慢,
尤其 get-permission-info 经常超时。根因是 ProjectSecurityWebFilter
每请求需校验"用户对项目是否授权",原实现走"拿全量 authorizedIds 再
contains"路径,超管分支还得 selectList 全表项目。Framework 层虽有
60s 本地缓存,cache miss 时仍要走 Feign HTTP 自调用 + 两次 DB。

优化:
1. 新增 ProjectService.isProjectAuthorized(userId, projectId) 单项校验:
   - 超管直通返回 true(不查任何表)
   - 普通用户走 (user_id, project_id) 唯一索引的 selectCount 单行查询
2. ProjectCommonApi / ProjectApiImpl / ProjectFrameworkService(Impl)
   全链路新增 isProjectAuthorized Feign 接口
3. ProjectFrameworkServiceImpl 为 isProjectAuthorized 加 60s 本地
   Guava 缓存(key=(userId,projectId));invalidateAuthorizedProjectCache
   同步清理本用户所有条目
4. ProjectSecurityWebFilter 改调 isProjectAuthorized,消除每请求
   拉全量列表的开销
5. ProjectServiceImpl.getDefaultProjectId 的 N 次 selectById
   改成一次 selectByIds 批量
6. AuthController.getPermissionInfo 第 107 行
   getUserRoleIdListByUserId → FromCache(yudao 原生小瑕疵顺手修)

预期收益:
- Filter 热路径在 cache 命中时 0 次 DB,cache miss 时 1 次单行查询
- get-permission-info 消除一次无缓存 user_role DB 查询

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:20:29 +08:00
lzh
423bf3ec3f feat(tenant): 实现 ProjectSecurityWebFilter 项目权限集合校验
新增 ProjectSecurityWebFilter:
- 集合校验: user.authorizedProjectIds.contains(header.projectId)
- 默认项目选择: DEFAULT编码 → 最小ID → 单项目自动选中 → 无授权403
- @ProjectIgnore URL 自动跳过
- 注册在 WebFilterOrderEnum.PROJECT_SECURITY_FILTER (-98)

框架层:
- ProjectCommonApi: 新增 getAuthorizedProjectIds, getDefaultProjectId
- ProjectFrameworkService: 新增授权查询 + Caffeine 缓存(60s/1000条)
- ViewshTenantAutoConfiguration: 注册 Filter + 扫描 @ProjectIgnore

业务层:
- ProjectService: 新增 getAuthorizedProjectIds, getDefaultProjectId
- ProjectServiceImpl: 默认项目3级回退逻辑
- ProjectApiImpl: 实现 Feign 端点

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 23:35:56 +08:00
lzh
c85f84ea46 test(tenant): Phase 4 — 项目隔离集成测试
新增测试 (33个全部通过):
- ProjectContextHolderTest (8 tests): set/get/clear/ignore/线程隔离
- ProjectUtilsTest (14 tests): execute/executeIgnore/嵌套调用/异常恢复
- DualInterceptorTest (11 tests): 双拦截器 SQL 注入验证 (已有)

DO 迁移验证:
- 15 个 DO 已迁移到 ProjectBaseDO (grep 确认)
- 3 个非迁移 DO 正确保持 TenantBaseDO

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:52:19 +08:00
lzh
a2f500fa20 feat(tenant): 租户-项目两级架构 Phase 2 — IoT + Ops 业务迁移
DO 迁移 (15个 TenantBaseDO → ProjectBaseDO):
- IoT: IotDeviceDO
- Ops 核心: OpsOrderDO, OpsOrderEventDO, OpsOrderDispatchDO, OpsOrderQueueDO,
  OpsBusAreaDO, OpsAreaDeviceRelationDO, OpsDeviceTrajectoryDO
- Ops 保洁: OpsOrderCleanExtDO, OpsCleanerStatusDO, OpsCleanerPerformanceMonthlyDO,
  OpsInspectionRecordDO, OpsInspectionRecordItemDO
- Ops 安保: OpsOrderSecurityExtDO, OpsAreaSecurityUserDO

IoT 适配:
- IotDeviceRespDTO 新增 projectId 字段
- IotDeviceMessage 新增 projectId 字段
- IotDeviceMessageServiceImpl.appendDeviceMessage() 设置 projectId
- IotCleanRuleMessageHandler 嵌套 ProjectUtils.execute() 设置项目上下文

缓存改造:
- ProjectRedisCacheManager extends TenantRedisCacheManager,追加 :projectId 后缀
- ViewshTenantAutoConfiguration 替换为 ProjectRedisCacheManager

SQL 迁移脚本 (sql/mysql/project/):
- 01-create-tables.sql: system_project + system_user_project 建表
- 02-default-data.sql: 默认项目 + 用户关联回填
- 03-alter-business-tables.sql: 15 张表添加 project_id (NULL → 回填 → NOT NULL → 索引)
- 04-index-audit.sql: 现有索引审计 + project_id 补充建议
- 99-rollback.sql: 完整回滚方案

附带修复:
- fix(ops): UserDispatchStatusServiceImpl 添加缺失的 KEY_PREFIX 常量

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:27:34 +08:00
lzh
87beb1228e feat(tenant): 租户-项目两级架构 Phase 0+1 — 基础框架层
Phase 0 技术验证:
- ProjectBaseDO extends TenantBaseDO,新增 projectId 字段
- ProjectContextHolder (TransmittableThreadLocal) 项目上下文管理
- ProjectDatabaseInterceptor 实现 TenantLineHandler,返回 project_id 列
- 注册第二个 TenantLineInnerInterceptor,通过 @Qualifier 保证初始化顺序
- DualInterceptorTest 11 个用例验证双拦截器 SQL 注入(SELECT/INSERT/UPDATE/DELETE + JOIN + 子查询)

Phase 1 基础框架层:
- @ProjectIgnore 注解 + ProjectIgnoreAspect (SpEL 条件支持)
- ProjectUtils 工具类 (execute/executeIgnore)
- ProjectContextWebFilter 从请求 Header 解析 project-id
- WebFrameworkUtils 扩展 HEADER_PROJECT_ID + getProjectId()
- WebFilterOrderEnum 新增 PROJECT_CONTEXT_FILTER、PROJECT_SECURITY_FILTER
- RPC: TenantRequestInterceptor 自动透传 project-id
- MQ: Kafka/RocketMQ/RabbitMQ/Redis 全部支持 project-id 发送与消费
- @ProjectJob + ProjectJobAspect (@Order(2) 内层,配合 @TenantJob 使用)
- TenantJobAspect 补充 @Order(1) 外层标记
- ProjectDO + UserProjectDO + Mapper + ProjectService + ProjectController
- ProjectCommonApi (Feign) + ProjectApiImpl + ProjectFrameworkServiceImpl (Guava 缓存)
- TenantServiceImpl.createTenant() 联动创建默认项目
- ErrorCodeConstants 新增 1-002-030-xxx 项目错误码

Review 修复:
- Bean 初始化顺序: projectLineInnerInterceptor 依赖 @Qualifier 确保顺序
- computeIgnoreTable: @ProjectIgnore 检查优先于 isAssignableFrom
- ProjectFrameworkServiceImpl 注册为 Spring Bean
- RocketMQ SendHook: project-id 独立于 tenantId 传播
- createDefaultProject 移入 TenantUtils.execute 事务块内
- 全部 MQ/RPC 统一使用 HEADER_PROJECT_ID 常量
- ProjectJobAspect 增加租户上下文防御校验
- 移除 ProjectDO/UserProjectDO 无效的 @KeySequence
- ProjectServiceImpl/ProjectApiImpl 移除冗余 TenantUtils.execute 嵌套

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 19:22:57 +08:00
lzh
e11d3e1b6e feat(framework): OssPresignResponseBodyAdvice 支持 List<String> 字段预签名
- @OssPresignUrl 注解现在同时适用于 String 和 List<String> 字段
- 回填时防御不可变 List,自动降级为 ArrayList
- FileServiceImpl 预签名访问 URL 去除查询参数,保持持久化路径干净

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 14:59:34 +08:00
lzh
f3299bd655 feat(framework): 新增 @OssPresignUrl 注解与 ResponseBodyAdvice 自动预签名框架
基于 ResponseBodyAdvice 拦截 CommonResult 响应体,通过反射递归扫描
VO 中标注 @OssPresignUrl 的 String 字段,去重后批量调用
OssPresignUrlApi 一次性完成预签名,再回填到对应字段。

核心设计:
- supports() 阶段通过泛型静态分析判断 VO 是否含注解字段,
  无注解的接口零开销跳过(类似字典翻译注解思路)
- 三级缓存:FIELD_CACHE / ALL_FIELDS_CACHE / HAS_PRESIGN_CACHE
- 递归深度限制 MAX_SCAN_DEPTH=10 防止 StackOverflow
- 仅扫描 com.viewsh.* 包,规避 Java 17 模块系统限制
- 异常静默降级,保留原始 URL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 15:05:42 +08:00
lzh
2a20f7a89f fix(framework): ApiRequestFilter 纳入 /open-api 路径,修复 open-api 多租户拦截缺失
TenantSecurityWebFilter 继承 ApiRequestFilter,之前 shouldNotFilter 仅匹配
/admin-api 和 /app-api,导致 /open-api 请求跳过租户校验,DB 层
getRequiredTenantId() 抛 NPE。现在补上 openApi prefix,外部系统需传
tenant-id Header。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:02:02 +08:00
lzh
6e56dcb6a2 feat(framework): API 签名、安全白名单与 Web 配置调整
- 新增 ApiSignatureProperties 配置类
- 调整签名自动配置与 Redis DAO 实现
- 更新安全白名单与 Web 属性配置
- 网关新增安保模块路由配置

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 17:35:05 +08:00
lzh
2a1cdfc4dc Merge remote-tracking branch 'origin/master' into merge-temp 2026-01-14 22:49:28 +08:00
lzh
14f9015939 fix: Jenkins修复4-开启Spring Boot Admin
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
2026-01-14 12:22:55 +08:00
lzh
ee0304e120 chore: banner修改 2025-12-31 17:29:28 +08:00
lzh
8ccfafe2bb first commit
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
2025-12-31 11:48:19 +08:00