Files
ljwx-health/docs/07-compliance/multi-tenant-checkstyle-guide.md
brunoandClaude Sonnet 4.5 c19f4e225a feat(alert): Alert V2.1 P1-2 完整实施 - 告警升级机制 + 用户服务集成
🎯 Alert V2.1 P1-2: Alert Escalation Mechanism - 100% Complete

核心功能:
- ✅ 时间窗口升级 (30分钟超时自动升级优先级)
- ✅ 重复次数升级 (≥3次触发自动升级)
- ✅ 组合触发升级 (TIME_WINDOW + REPEAT_COUNT)
- ✅ 通知扩散 (TEAM/MANAGER/ADMIN自动扩展通知对象)
- ✅ 升级历史审计 (完整追溯链)
- ✅ 批量处理优化 (100条/批次)
- ✅ 幂等性保证 (防止重复升级)

用户服务集成 (本次提交重点):
- ✅ queryTeamUsers() - 查询组织所有成员 (sys_user_org)
- ✅ queryManagers() - 查询组织主管 (sys_user_org.principal=1)
- ✅ queryAdmins() - 查询租户管理员 (sys_user.userType>=2)

技术实现:
- Service: AlertEscalationServiceImpl.java (~600 lines)
- Scheduled Task: AlertEscalationWorker.java (每5分钟执行)
- Database: V2.17.3 migration (escalation_rule + escalation_history)
- Integration Tests: AlertV21P1_2_EscalationIntegrationTest.java (9 scenarios)
- User Integration: SysUserMapper + SysUserOrgMapper (MyBatis-Plus)

代码质量:
- ✅ Checkstyle: 0 violations
- ✅ Multi-tenant: Proper customer_id isolation + suppressions
- ✅ Error handling: Graceful degradation with logging
- ✅ Performance: Batch processing + caching
- ✅ Type safety: LambdaQueryWrapper queries

配置:
- ljwx.alert.escalation.enabled=true (feature toggle)
- Cron: 0 */5 * * * ? (every 5 minutes)

测试修复:
- AlertV21P0IntegrationTest.java (6 errors fixed)
- AlertV21P1IntegrationTest.java (2 errors fixed)
- AlertV21P1_2_EscalationIntegrationTest.java (11 errors fixed)
- PhysicalSignStreamCacheTest.java (import conflicts resolved)
- TenantInterceptorOrderTest.java (method override fixed)

文档:
- alert-v2-1-p1-2-completion-report.md
- alert-v2-1-p1-2-implementation-summary.md
- alert-v2-1-p1-2-user-service-integration.md

已知限制:
- Integration test execution blocked by Spring context circular dependency
- Manual testing required in dev environment

部署就绪:
- [x] 源代码实现完整
- [x] 数据库迁移脚本
- [x] 配置文件更新
- [x] 静态检查通过
- [x] 文档完整
- [ ] 集成测试执行 (基础设施问题阻塞)
- [ ] 开发环境手动测试

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-29 15:03:04 +08:00

8.2 KiB
Raw Permalink Blame History

多租户 Checkstyle 验证指南

📋 概述

本项目使用 Maven Checkstyle 插件强制执行多租户安全规范,防止跨租户数据泄露。所有代码提交前必须通过多租户 Checkstyle 验证。


🎯 核心规则(5条)

规则1: 禁止使用 DTO.getCustomerId()

❌ 错误示例:

// Controller 或 Service 层
wrapper.eq("customer_id", dto.getCustomerId());  // 违规!
submitDTO.getCustomerId();                       // 违规!

✅ 正确做法:

// 从安全的 ThreadLocal 上下文获取
Long customerId = UserContext.getCustomerId();
wrapper.eq("customer_id", customerId);

原因: 前端可能篡改 DTO 中的 customerId,必须从已验证的 ThreadLocal 上下文获取。


规则2: 禁止手动设置 Entity.customerId

❌ 错误示例:

// Service 层
entity.setCustomerId(dto.getCustomerId());        // 违规!
message.setCustomerId(UserContext.getCustomerId()); // 也违规!

✅ 正确做法:

// 不需要手动设置,让 MyBatis-Plus 拦截器自动注入
TDeviceMessage message = new TDeviceMessage();
message.setDeviceSn(dto.getDeviceSn());
// message.setCustomerId(...);  // 删除这行!
deviceMessageService.save(message);  // 拦截器会自动注入 customer_id

原因: MyBatis-Plus 租户拦截器会在 INSERT/UPDATE 时自动注入当前租户 ID,手动设置可能导致安全漏洞。


规则3: Service 层禁用 getCustomerIdOrDefault()

❌ 错误示例:

// Service 层
Long customerId = UserContext.getCustomerIdOrDefault();  // 违规!

✅ 正确做法:

// 使用 fail-fast 机制
Long customerId = UserContext.getCustomerId();  // 上下文缺失时会抛异常

例外: 仅系统定时任务(Job)可以使用 getCustomerIdOrDefault(),业务代码必须使用 getCustomerId()。

原因: getCustomerIdOrDefault() 会返回 0L 作为默认值,造成"隐形共享区",导致数据泄露。


规则4: 禁止在 Service 中直接使用 request.getCustomerId()

❌ 错误示例:

public void saveUser(UserRequest request) {
    Long customerId = request.getCustomerId();  // 违规!
}

✅ 正确做法:

public void saveUser(UserRequest request) {
    Long customerId = UserContext.getCustomerId();  // 从上下文获取
}

原因: 前端 request 可能被篡改,必须从已验证的 ThreadLocal 上下文获取。


规则5: 禁止 SQL 字符串拼接 customerId

❌ 错误示例:

// SQL 注入风险
String sql = "SELECT * FROM sys_user WHERE customer_id = " + customerId + " AND ...";

✅ 正确做法:

// 使用参数化查询
QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
wrapper.eq("customer_id", customerId);

原因: 防止 SQL 注入攻击,必须使用参数化查询。


🛠️ 如何使用

本地验证

# 1. 编译时自动验证(推荐)
cd ljwx-boot
mvn clean compile

# 2. 单独运行 Checkstyle 验证
mvn checkstyle:check

# 3. 仅验证多租户规则
mvn checkstyle:check -Dcheckstyle.config.location=code-quality/checkstyle-multi-tenant.xml

# 4. 生成 HTML 报告
mvn checkstyle:checkstyle
# 报告位置: target/site/checkstyle.html

CI/CD 自动验证

GitHub Actions / Gitea Actions 在 mvn clean install 阶段会自动执行多租户验证:

- name: Build with Maven
  run: mvn clean install -DskipTests
  # 会自动运行 validate-multi-tenant 阶段

验证失败时:

  • 编译会中止(failsOnError=true)
  • 控制台输出详细违规信息
  • 必须修复所有违规才能通过编译

📝 配置文件

Checkstyle 规则文件

位置: ljwx-boot/code-quality/checkstyle-multi-tenant.xml

<module name="RegexpSinglelineJava">
    <property name="format" value="\.getCustomerId\(\)"/>
    <property name="message" value="❌ 多租户安全违规: 禁止使用DTO.getCustomerId()..."/>
</module>

Maven 插件配置

位置: ljwx-boot/pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.5.0</version>
    <executions>
        <execution>
            <id>validate-multi-tenant</id>
            <phase>validate</phase>
            <goals>
                <goal>check</goal>
            </goals>
            <configuration>
                <configLocation>code-quality/checkstyle-multi-tenant.xml</configLocation>
                <failsOnError>true</failsOnError>
                <violationSeverity>warning</violationSeverity>
            </configuration>
        </execution>
    </executions>
</plugin>

🔧 如何修复违规

自动化修复脚本(推荐)

# 位置: ljwx-boot/scripts/fix-multi-tenant-violations.sh
cd ljwx-boot
./scripts/fix-multi-tenant-violations.sh

# 该脚本会自动:
# 1. 扫描所有违规代码
# 2. 批量替换为正确写法
# 3. 生成修复报告

手动修复步骤

  1. 运行验证获取违规列表:

    mvn checkstyle:check 2>&1 | grep "多租户" > violations.txt
    
  2. 逐个修复违规文件:

    • 打开 violations.txt 查看违规位置
    • 参照上述"正确做法"进行修复
  3. 重新验证:

    mvn clean compile
    

✅ 验收标准

编译通过标准

mvn clean compile
# 应该看到:
# [INFO] BUILD SUCCESS
# [INFO] You have 0 Checkstyle violations.

集成测试验证

# 运行多租户隔离测试
mvn test -Dtest=MultiTenantIsolationTest

# 所有测试应该通过:
# ✅ testTenantA_CannotAccessTenantB_Data
# ✅ testTenantContextMissing_ThrowsException
# ✅ testTenantScope_CorrectSwitching
# ✅ testInsert_ForcesCustomerIdOverride
# ✅ testUpdate_RespectsTenantIsolation
# ✅ testDelete_RespectsTenantIsolation

🚨 常见问题

Q1: 编译失败提示 "You have 264 Checkstyle violations"

A: 说明代码中存在 264 处多租户违规,必须全部修复才能编译通过。

解决方案:

# 1. 生成详细报告
mvn checkstyle:checkstyle
open target/site/checkstyle.html  # 查看详细违规位置

# 2. 使用自动化脚本修复
./scripts/fix-multi-tenant-violations.sh

# 3. 手动修复剩余违规(如果有)

Q2: 如何临时跳过验证(不推荐)

仅在紧急情况下使用,必须在后续立即修复:

# 跳过所有 Checkstyle 验证
mvn clean compile -Dcheckstyle.skip=true

注意: 跳过验证的代码禁止合并到主分支,必须在 PR 前完成修复。


Q3: 某些文件需要豁免怎么办?

在文件中添加抑制注释:

// CHECKSTYLE.OFF: RegexpSinglelineJava
Long customerId = dto.getCustomerId();  // 特殊场景,已人工审查
// CHECKSTYLE.ON: RegexpSinglelineJava

豁免条件(必须同时满足):

  1. 技术负责人审查通过
  2. 添加详细的安全评估注释
  3. 记录在安全例外清单中

📊 违规统计

当前状态(2026-01-28)

模块 违规数 状态
ljwx-boot-modules 264 🔴 待修复
ljwx-boot-common 0 ✅ 已通过
ljwx-boot-infrastructure 0 ✅ 已通过
ljwx-boot-admin 0 ✅ 已通过

违规类型分布

规则 违规数 占比
规则1: dto.getCustomerId() ~180 68%
规则2: entity.setCustomerId() ~60 23%
规则3: getCustomerIdOrDefault() ~15 6%
规则4: request.getCustomerId() ~8 3%
规则5: SQL 字符串拼接 ~1 <1%

🔗 相关文档


📞 支持

遇到问题请联系:

  • 技术负责人: 查看 CODEOWNERS 文件
  • 文档反馈: 提交 Issue 到项目仓库
  • 紧急支持: 参考 CONTRIBUTING.md

最后更新: 2026-01-28 版本: V1.0 维护者: LJWX Health 架构团队