CRM 四层数据权限方案

CRM 四层数据权限方案

核心定位

一句话说清楚:在 Yudao 原生 @CrmPermission 注解基础上,构建「用户-角色-岗位-部门」四层数据权限 + 客户等级级联过滤的完整权限体系。

解决什么问题

层级 当前状态 增强后
用户级 ✅ 支持 ✅ 保持
角色级 ❌ 不支持 ✅ 角色-权限关联
岗位级 ❌ 不支持 ✅ 岗位-权限关联
部门级 ❌ 不支持 ✅ 部门-权限关联
客户等级 ❌ 不支持 ✅ 等级叠加 + 级联过滤

适合什么样的用户

  • 需要精细化数据权限控制的 CRM 系统
  • 有客户等级分层管理需求的企业
  • 需要按部门/岗位隔离客户数据的组织

1. 四层数据权限模型

graph TB subgraph "权限决策引擎" A["用户请求"] --> B["权限解析"] B --> C["权限合并
取并集"] C --> D["数据范围过滤"] D --> E["客户等级过滤
AND 叠加"] end subgraph "权限来源" F["用户级权限
优先级 1 (最高)"] G["角色级权限
优先级 2"] H["岗位级权限
优先级 3"] I["部门级权限
优先级 4 (最低)"] end F --> B G --> B H --> B I --> B E --> J["SQL 过滤"] J --> K["返回结果"]

2. 权限校验流程

2.1 操作权限校验

sequenceDiagram participant User as 用户 participant Controller as Controller participant Aspect as @CrmPermission Aspect participant Engine as 权限引擎 participant DB as 数据库 User->>Controller: 请求操作客户 Controller->>Aspect: 触发权限校验 Aspect->>Engine: hasBizOperationPermission() Engine->>Engine: 检查用户级权限 Engine->>Engine: 检查角色级权限 Engine->>Engine: 检查岗位级权限 Engine->>Engine: 检查部门级权限 Engine->>Engine: 合并结果 (取并集) alt 有权限 Engine->>Aspect: 返回 true Aspect->>Controller: 放行 Controller->>DB: 执行业务操作 else 无权限 Engine->>Aspect: 返回 false Aspect->>Controller: 抛出权限异常 end

2.2 数据权限过滤流程

sequenceDiagram participant User as 用户 participant Controller as Controller participant Interceptor as MyBatis 拦截器 participant Engine as 权限引擎 participant DB as 数据库 User->>Controller: 查询客户列表 Controller->>Interceptor: 触发 SQL 拦截 Interceptor->>Engine: buildDataScopeSql() Engine->>Engine: 获取数据范围条件 Engine->>Engine: 获取客户等级条件 Engine->>Engine: 判断是否级联 (关联表) Engine->>Interceptor: 返回 SQL 过滤条件 Interceptor->>Interceptor: 注入 WHERE 条件 Interceptor->>DB: 执行过滤后的 SQL DB->>User: 返回过滤结果

3. 数据库表结构

3.1 业务对象操作权限表

CREATE TABLE `crm_biz_object_permission` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
    `biz_type` INT NOT NULL COMMENT '业务对象类型(1线索/2客户/3联系人/4商机/5合同)',
    `biz_type_name` VARCHAR(50) NOT NULL COMMENT '业务对象名称',
    `operation_type` VARCHAR(20) NOT NULL COMMENT '操作类型(CREATE/READ/UPDATE/DELETE/TRANSFER)',
    `operation_name` VARCHAR(50) NOT NULL COMMENT '操作名称',
    `role_id` BIGINT DEFAULT NULL COMMENT '角色ID',
    `post_id` BIGINT DEFAULT NULL COMMENT '岗位ID',
    `dept_id` BIGINT DEFAULT NULL COMMENT '部门ID',
    `user_id` BIGINT DEFAULT NULL COMMENT '用户ID',
    `status` TINYINT DEFAULT 1 COMMENT '状态(0禁用/1启用)',
    `creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
    `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
    `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted` BIT DEFAULT 0 COMMENT '是否删除',
    `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
    PRIMARY KEY (`id`),
    KEY `idx_biz_type` (`biz_type`),
    KEY `idx_role_id` (`role_id`),
    KEY `idx_post_id` (`post_id`),
    KEY `idx_dept_id` (`dept_id`),
    KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='业务对象操作权限表';

3.2 数据权限范围表(含客户等级)

CREATE TABLE `crm_data_scope_permission` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
    `biz_type` INT NOT NULL COMMENT '业务对象类型',
    `scope_type` VARCHAR(20) NOT NULL COMMENT '数据范围类型(ALL/SELF/DEPT/DEPT_AND_CHILD/CUSTOM)',
    `scope_value` TEXT COMMENT '自定义范围值(JSON格式)',
    `max_customer_level` INT DEFAULT NULL COMMENT '最大客户等级(NULL=不限制)',
    `role_id` BIGINT DEFAULT NULL COMMENT '角色ID',
    `post_id` BIGINT DEFAULT NULL COMMENT '岗位ID',
    `dept_id` BIGINT DEFAULT NULL COMMENT '部门ID',
    `user_id` BIGINT DEFAULT NULL COMMENT '用户ID',
    `status` TINYINT DEFAULT 1 COMMENT '状态(0禁用/1启用)',
    `creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
    `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
    `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted` BIT DEFAULT 0 COMMENT '是否删除',
    `tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户编号',
    PRIMARY KEY (`id`),
    KEY `idx_biz_type` (`biz_type`),
    KEY `idx_role_id` (`role_id`),
    KEY `idx_post_id` (`post_id`),
    KEY `idx_dept_id` (`dept_id`),
    KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限范围表';

3.3 数据范围类型说明

范围类型 说明 SQL 过滤逻辑
ALL 全部数据 无过滤条件
SELF 自己的数据 owner_user_id = current_user
DEPT 本部门数据 dept_id IN (current_dept)
DEPT_AND_CHILD 本部门及子部门 dept_id IN (current_dept_and_children)
CUSTOM 自定义范围 根据 scope_value 生成过滤条件

3.4 客户等级过滤说明

等级配置 说明 SQL 过滤逻辑
NULL 不限制客户等级 无过滤条件
0 仅 Level0 level = 0
1 <= Level1 level <= 1
2 <= Level2 level <= 2

4. 权限引擎核心实现

@Service
public class CrmPermissionEngineServiceImpl implements CrmPermissionEngineService {

    @Override
    public boolean hasBizOperationPermission(Long userId, Integer bizType, String operationType) {
        // 按优先级从高到低检查:用户 → 角色 → 岗位 → 部门
        if (hasUserPermission(userId, bizType, operationType)) return true;
        if (hasRolePermission(userId, bizType, operationType)) return true;
        if (hasPostPermission(userId, bizType, operationType)) return true;
        if (hasDeptPermission(userId, bizType, operationType)) return true;
        return false;
    }

    @Override
    public String buildDataScopeSql(Long userId, Integer bizType) {
        DataScopePermissionDO scope = getDataScope(userId, bizType);
        if (scope == null) return "1=0";

        StringBuilder sqlBuilder = new StringBuilder();

        // 数据范围过滤
        switch (scope.getScopeType()) {
            case "ALL": break;
            case "SELF": sqlBuilder.append("owner_user_id = ").append(userId); break;
            case "DEPT": sqlBuilder.append("dept_id = ").append(getUserDeptId(userId)); break;
            case "DEPT_AND_CHILD": sqlBuilder.append("dept_id IN (").append(getUserDeptAndChildIds(userId)).append(")"); break;
            case "CUSTOM": sqlBuilder.append(scope.getScopeValue()); break;
            default: return "1=0";
        }

        // 客户等级过滤(AND 叠加)
        Integer maxLevel = scope.getMaxCustomerLevel();
        if (maxLevel != null) {
            if (sqlBuilder.length() > 0) sqlBuilder.append(" AND ");
            sqlBuilder.append("level <= ").append(maxLevel);
        }

        return sqlBuilder.toString();
    }
}

5. MyBatis 数据权限拦截器

@Component
@Intercepts({@Signature(type = Executor.class, method = "query",
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class CrmDataPermissionInterceptor implements Interceptor {

    // 需要通过 customer_id 关联客户表进行等级级联过滤的表
    private static final Set<String> CASCADE_CUSTOMER_LEVEL_TABLES = Set.of(
        "crm_business", "crm_contract", "crm_contact",
        "crm_receivable", "crm_receivable_plan"
    );

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 1. 判断是否需要数据权限过滤
        // 2. 获取当前用户ID
        // 3. 解析业务类型
        // 4. 构建数据权限过滤条件
        // 5. 修改 SQL,添加 WHERE 过滤条件
        // 6. 执行查询
    }
}

级联关联关系

graph TB subgraph "客户等级级联" CUSTOMER["客户表
crm_customer
level 字段"] -->|customer_id| CONTACT["联系人
crm_contact"] CUSTOMER -->|customer_id| CONTRACT["合同
crm_contract"] CUSTOMER -->|customer_id| RECEIVABLE["回款
crm_receivable"] CUSTOMER -->|customer_id| RECEIVABLE_PLAN["回款计划
crm_receivable_plan"] CUSTOMER -->|customer_id| BUSINESS["商机
crm_business"] end CLUE["线索
crm_clue"] -.->|不级联| CUSTOMER
业务对象 关联字段 是否级联 说明
客户 level ❌ 源 直接应用等级条件
联系人 customer_id ✅ 是 通过客户ID关联继承等级
合同 customer_id ✅ 是 通过客户ID关联继承等级
回款 customer_id ✅ 是 通过客户ID关联继承等级
商机 customer_id ✅ 是 通过客户ID关联继承等级
线索 - ❌ 否 线索不关联客户

6. 前端权限配置界面

graph TB subgraph "CRM 权限管理" subgraph "权限层级切换" A1["部门权限"] A2["岗位权限"] A3["角色权限"] A4["用户权限"] end subgraph "业务对象选择" B1["客户"] B2["商机"] B3["合同"] B4["联系人"] B5["线索"] B6["回款"] end subgraph "操作权限配置" C1["创建"] C2["查看"] C3["编辑"] C4["删除"] C5["转移"] C6["导出"] end subgraph "数据范围配置" D1["全部数据"] D2["自己的数据"] D3["本部门数据"] D4["本部门及子部门"] D5["自定义范围"] end subgraph "客户等级过滤" E1["全部等级"] E2["Level0"] E3["<= Level1"] E4["<= Level2"] end end

7. 实施进度

阶段 任务 状态
Phase 1 数据库表结构设计与创建 ✅ 已完成
Phase 2 后端实体类与 Mapper ✅ 已完成
Phase 3 权限引擎服务实现 ✅ 已完成
Phase 4 MyBatis 数据权限拦截器 ✅ 已完成
Phase 5 API 接口实现 ✅ 已完成
Phase 6 前端页面开发 ✅ 已完成
Phase 7 客户等级级联过滤 ✅ 已完成
Phase 8 测试与验证 ✅ 已完成

总结

本方案实现了基于 部门-岗位-角色-用户 的四层数据权限过滤机制:

  1. 操作权限:通过 crm_biz_object_permission 表管理,四层优先级检查
  2. 数据范围:支持 ALL/SELF/DEPT/DEPT_AND_CHILD/CUSTOM 五种范围
  3. 客户等级过滤max_customer_level 字段,支持等级范围叠加过滤
  4. 级联继承:合同、联系人等通过 customer_id 自动继承客户等级限制
  5. SQL 拦截器:自动注入 WHERE 条件,无需修改现有业务代码
  6. 前端配置:统一的权限配置界面,支持层级切换和等级配置
docs