客户数据权限控制实现指南

📅 创建日期:2025-10-27
📌 版本:v1.0

📋 目录

  1. 实现概述
  2. 必须执行:数据库迁移
  3. 待完成:Service 类修改
  4. 测试验证
  5. 故障排查

实现概述

已完成的工作 ✅

  1. DataScope 注解扩展 - 添加了 customerAlias 参数
  2. DataScopeAspect 切面扩展 - 实现了客户权限过滤逻辑(DATA_SCOPE_CUSTOMER = “6”)
  3. 6个 Mapper XML 修改 - 所有查询都已添加 ${params.dataScope} 占位符
  4. Domain 实体类更新 - 子任务和处理记录添加了 customerId 字段
  5. 数据库迁移脚本创建 - db/add_customer_id_to_subtask_tables.sql
  6. BzCustomerServiceImpl - 已添加 @DataScope 注解

待完成的工作 ⏸️

还需要为5个 Service 实现类添加 @DataScope 注解


必须执行:数据库迁移

⚠️ 重要提示

在修改 Service 类之前,必须先执行数据库迁移脚本!

执行步骤

# 进入项目目录
cd H:\gitea-code-2025\HuaweiCloud\husky-afterservice

# 执行数据库脚本
mysql -u root -p husky_afterservice_db < db/add_customer_id_to_subtask_tables.sql

脚本功能

该脚本会自动完成以下操作:

  1. ✅ 为 bz_work_order_subtask 表添加 customer_id 字段
  2. ✅ 为 bz_subtask_process_record 表添加 customer_id 字段
  3. ✅ 从工单表回填历史数据的 customer_id
  4. ✅ 创建索引 idx_customer_id 以提升查询性能
  5. ✅ 输出数据完整性验证报告

验证迁移结果

执行以下 SQL 验证数据完整性:

-- 应该没有空值或不匹配的记录
SELECT
    'bz_work_order_subtask' AS table_name,
    COUNT(*) AS total,
    COUNT(customer_id) AS filled,
    COUNT(*) - COUNT(customer_id) AS missing
FROM bz_work_order_subtask
UNION ALL
SELECT
    'bz_subtask_process_record',
    COUNT(*),
    COUNT(customer_id),
    COUNT(*) - COUNT(customer_id)
FROM bz_subtask_process_record;

待完成:Service 类修改

修改清单

需要为以下5个 Service 实现类添加 @DataScope 注解:

# Service 类 文件路径 方法名 customerAlias 状态
1 BzProjectServiceImpl .../service/impl/BzProjectServiceImpl.java selectBzProjectList p ⏸️ 待完成
2 BzProjectEquipmentServiceImpl .../service/impl/BzProjectEquipmentServiceImpl.java selectBzProjectEquipmentList pe ⏸️ 待完成
3 BzWorkOrderServiceImpl .../service/impl/BzWorkOrderServiceImpl.java selectBzWorkOrderList w ⏸️ 待完成
4 BzWorkOrderSubtaskServiceImpl .../service/impl/BzWorkOrderSubtaskServiceImpl.java selectBzWorkOrderSubtaskList st ⏸️ 待完成
5 BzSubtaskProcessRecordServiceImpl .../service/impl/BzSubtaskProcessRecordServiceImpl.java selectBzSubtaskProcessRecordList r ⏸️ 待完成

修改步骤(针对每个类)

步骤1:添加 import 语句

在文件顶部的 import 区域添加:

import com.husky.common.annotation.DataScope;

步骤2:添加注解

selectXxxList 方法的 @Override 注解下方添加:

@DataScope(customerAlias = "表别名")

示例:BzProjectServiceImpl

修改前:

@Override
public List<BzProject> selectBzProjectList(BzProject bzProject)
{
    return bzProjectMapper.selectBzProjectList(bzProject);
}

修改后:

import com.husky.common.annotation.DataScope;

...

@Override
@DataScope(customerAlias = "p")
public List<BzProject> selectBzProjectList(BzProject bzProject)
{
    return bzProjectMapper.selectBzProjectList(bzProject);
}

customerAlias 对照表

确保 customerAlias 与 Mapper XML 中的表别名完全一致:

Service Mapper XML 中的别名 customerAlias 值
BzProjectServiceImpl p (from bz_project p) "p"
BzProjectEquipmentServiceImpl pe (from bz_project_equipment pe) "pe"
BzWorkOrderServiceImpl w (from bz_work_order w) "w"
BzWorkOrderSubtaskServiceImpl st (from bz_work_order_subtask st) "st"
BzSubtaskProcessRecordServiceImpl r (from bz_subtask_process_record r) "r"

测试验证

测试前准备

  1. ✅ 确认数据库迁移已执行
  2. ✅ 确认所有 Service 类已添加注解
  3. ✅ 重新编译项目:mvn clean package
  4. ✅ 重启应用服务器

测试场景

测试1:单客户权限

步骤:

  1. 创建测试角色”角色A”,设置 data_scope = '6'
  2. 在角色管理界面,为”角色A”授权客户1
  3. 创建测试用户,分配”角色A”
  4. 使用该用户登录系统
  5. 查询客户列表、项目列表、工单列表

预期结果:

  • 只能看到客户1的数据
  • 只能看到客户1的项目
  • 只能看到客户1的工单

测试2:多客户权限

步骤:

  1. 修改”角色A”,授权客户1、2、3
  2. 登录查询

预期结果:

  • 可以看到客户1、2、3的所有数据

测试3:超级管理员

步骤:

  1. 使用 admin 账号登录
  2. 查询所有数据

预期结果:

  • 可以看到所有客户的数据(权限检查被跳过)

验证 SQL 是否正确生成

开启 MyBatis SQL 日志(application.yml):

mybatis:
    configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重启后,查询列表时会在控制台看到类似的 SQL:

SELECT * FROM bz_customer
WHERE del_flag = '0'
AND bz_customer.customer_id IN (
    SELECT customer_id FROM sys_role_customer WHERE role_id = 100
)

故障排查

问题1:权限不生效,可以看到所有数据

排查步骤:

  1. 检查角色的 data_scope 字段:

    SELECT role_id, role_name, data_scope FROM sys_role WHERE role_id = ?;

    应该为 '6'

  2. 检查 sys_role_customer 表是否有数据:

    SELECT * FROM sys_role_customer WHERE role_id = ?;
  3. 检查 Service 方法是否添加了 @DataScope 注解

  4. 清理缓存并重启应用

问题2:查询结果为空

排查步骤:

  1. 检查 customerAlias 是否正确:
    `java
    // 错误示例(别名不匹配)
    @DataScope(customerAlias = “customer”) // XML中是 bz_customer

// 正确示例
@DataScope(customerAlias = “bz_customer”) // 与XML一致


2. 检查表中是否有 `customer_id` 数据:
```sql
SELECT COUNT(*) FROM bz_customer WHERE customer_id IS NOT NULL;
  1. 检查生成的 SQL(查看日志)

问题3:子任务数据不一致

症状: 子任务的 customer_id 与工单不匹配

解决方案:

  1. 重新执行数据回填:

    UPDATE bz_work_order_subtask st
    INNER JOIN bz_work_order wo ON st.order_id = wo.order_id
    SET st.customer_id = wo.customer_id;
  2. 检查应用层代码是否正确设置 customer_id


权限过滤原理

SQL 生成示例

原始查询:

SELECT * FROM bz_work_order w
WHERE w.del_flag = '0'

添加权限过滤后:

SELECT * FROM bz_work_order w
WHERE w.del_flag = '0'
AND w.customer_id IN (
    SELECT customer_id FROM sys_role_customer WHERE role_id = 100
)

多角色权限合并

当用户拥有多个角色时:

WHERE (
    w.customer_id IN (SELECT customer_id FROM sys_role_customer WHERE role_id = 100)
    OR w.customer_id IN (SELECT customer_id FROM sys_role_customer WHERE role_id = 101)
)

附录:完整修改清单

已修改的文件 ✅

类型 文件名 说明
注解 DataScope.java 添加 customerAlias 参数
切面 DataScopeAspect.java 实现客户权限过滤逻辑
Mapper BzCustomerMapper.xml 添加权限过滤占位符
Mapper BzProjectMapper.xml 添加权限过滤占位符
Mapper BzProjectEquipmentMapper.xml 添加权限过滤占位符
Mapper BzWorkOrderMapper.xml 添加权限过滤占位符
Mapper BzWorkOrderSubtaskMapper.xml 添加权限过滤占位符
Mapper BzSubtaskProcessRecordMapper.xml 添加权限过滤占位符
Domain BzWorkOrderSubtask.java 添加 customerId 字段
Domain BzSubtaskProcessRecord.java 添加 customerId 字段
Service BzCustomerServiceImpl.java 添加 @DataScope 注解
SQL add_customer_id_to_subtask_tables.sql 数据库迁移脚本

待修改的文件 ⏸️

文件名 需要添加的内容
BzProjectServiceImpl.java @DataScope(customerAlias = "p")
BzProjectEquipmentServiceImpl.java @DataScope(customerAlias = "pe")
BzWorkOrderServiceImpl.java @DataScope(customerAlias = "w")
BzWorkOrderSubtaskServiceImpl.java @DataScope(customerAlias = "st")
BzSubtaskProcessRecordServiceImpl.java @DataScope(customerAlias = "r")

快速参考

角色配置流程

  1. 登录系统 → 系统管理 → 角色管理
  2. 新建/编辑角色
  3. 设置数据范围为”客户数据权限”
  4. 在客户权限标签页勾选授权的客户
  5. 保存

权限类型说明

数据范围 代码 说明
全部数据权限 1 查看所有数据
自定义数据权限 2 基于部门
部门数据权限 3 仅本部门
部门及以下 4 本部门+下级部门
仅本人数据 5 仅自己创建的
客户数据权限 6 仅授权的客户

如有疑问,请查看完整的技术文档或联系开发团队。

作者:聂盼盼  创建时间:2025-10-27 17:20
最后编辑:聂盼盼  更新时间:2025-10-28 19:53