Skip to main content
数据权限分级说明LangChat Pro产品采用分级权限控制策略:
  1. 强隔离层aigc_appaigc_workflowaigc_knowledge 三张核心业务表实施严格的数据隔离,默认遵循”创建者可见”原则,所有数据按用户隔离
  2. 菜单隔离层:其他业务表不进行数据过滤,仅通过 menu 菜单权限控制页面访问级别

一、架构概述

1.1 权限隔离策略

LangChat Pro对核心业务数据实施精细化权限管理,采用”默认私有 + 按需授权”的隔离模式。对于 aigc_app(AI应用)、aigc_workflow(工作流)、aigc_knowledge(知识库)三张表,系统默认实施用户级数据隔离,即每个用户只能访问自己创建的数据资源。 当需要跨用户协作时,数据创建者可通过授权机制将数据访问权限授予指定用户。这种设计既保证了数据的私密性与安全性,又提供了灵活的协作能力。

知识库权限特殊说明

知识库(aigc_knowledge)作为LangChat Pro的核心组件,其权限控制具有特殊的重要性:
  • 独立授权机制:知识库采用独立的数据权限配置,用户可自主选择将知识库共享给其他用户
  • Agent关联场景:当Agent被授权给其他用户使用时,若Agent关联的知识库未同时授权,被授权用户虽能在Agent配置中查看到知识库的关联关系,但在实际Chat对话的RAG检索过程中,系统将自动过滤该知识库,确保数据安全
权限继承与级联控制:Agent授权不会自动级联至关联的知识库,需分别进行权限配置。这种细粒度控制机制确保数据所有者对每一份数据资源都有完全的管控权。

1.2 权限配置操作

对于 aigc_appaigc_workflowaigc_knowledge 三张核心表,系统提供统一的权限配置入口: 操作路径:在对应资源列表页面 → 点击目标卡片 → 选择”授权”按钮 → 在授权用户列表中选择目标用户 → 确认授权 授权用户选择 权限配置确认

二、架构设计

2.1 设计理念

LangChat Pro采用分层权限控制 + 场景化按需过滤的多层权限过滤架构,在不同层级实施不同粒度的权限控制策略,既保证系统安全性,又确保查询性能。

2.1.1 架构层次图

┌─────────────────────────────────────────────────────────────┐
│                   表现层 (Presentation Layer)                │
│   - 应用列表页面、知识库管理页面、编辑页面等                       │
│   - 负责权限配置UI交互与用户操作反馈                             │
└───────────────────────────┬─────────────────────────────────┘


┌──────────────────────────────────────────────────────────────┐
│                   业务层 (Service Layer)                          │
│   - AigcAppService:应用业务逻辑处理                              │
│   - AigcKnowledgeService:知识库CRUD与管理                         │
│   - CoreChatService:对话交互与RAG检索核心服务                   │
└───────────────────────────┬──────────────────────────────────────┘

           ┌────────────────┴────────────────┐
           ▼                                 ▼
┌────────────────────┐          ┌───────────────────────────┐
│    全局拦截器       │          │   知识库权限过滤器         │
│ LcPermissionInterceptor│      │ KnowledgeAccessFilter     │
│                    │          │                           │
│ 功能职责:          │          │ 功能职责:                 │
│ - SQL自动注入与过滤 │          │ - 分页查询权限校验         │
│ - 应用/工作流数据隔离│          │ - RAG检索权限控制          │
│ - 拦截器链式处理    │          │ - 知识库授权状态检查       │
│                    │          │ - 场景化按需过滤           │
└─────────┬──────────┘          └────────────┬──────────────┘
          │                                 │
          ▼                                 ▼
┌─────────────────────────────────────────────────┐
│                   持久层 (Persistence Layer)     │
│   - MyBatis-Plus Mapper:数据访问对象             │
│   - aigc_data_access:权限关系存储表              │
│   - 数据库SQL执行与结果映射                        │
└─────────────────────────────────────────────────┘

2.2 核心设计原则

  1. 最小化全局拦截范围:全局拦截器仅对高频且必须隔离的核心业务表(aigc_appaigc_workflow)实施自动权限过滤,避免过度拦截影响性能
  2. 知识库差异化处理:鉴于知识库在不同业务场景下权限需求差异较大(如关联选择vs实际检索),采用独立的权限过滤器,在业务代码中按需显式调用
  3. 关注点分离(Separation of Concerns):权限逻辑与业务逻辑完全解耦,通过拦截器和过滤器独立实现,不侵入业务代码,便于维护与扩展
  4. 场景化按需过滤:根据业务场景特点灵活决定是否应用权限控制,例如知识库关联选择时不过滤(保证Agent配置完整性),但RAG检索时严格过滤(保证数据安全)
  5. 性能优先原则:通过SQL层面的权限过滤,在数据源端控制数据范围,避免应用层的大数据集过滤,确保查询效率

三、权限控制范围详解

3.1 全局拦截器控制的数据表

表名控制机制业务场景过滤规则
aigc_appMyBatis-Plus全局SQL拦截AI应用资源隔离creator = 当前用户 OR id IN (已授权的应用ID列表)
aigc_workflowMyBatis-Plus全局SQL拦截工作流资源隔离creator = 当前用户 OR id IN (已授权的工作流ID列表)
技术实现:通过 LcPermissionInterceptor 拦截MyBatis-Plus的SQL执行过程,在原始SQL语句中自动注入权限过滤条件,实现对应用和工作流数据的透明隔离。 优势
  • 对业务代码零侵入,开发者无需编写权限过滤逻辑
  • 在SQL执行层面控制数据范围,查询性能最优
  • 统一的权限控制策略,降低维护成本

3.2 知识库权限控制的场景化策略

知识库作为Agent的核心数据源,其权限控制需在不同场景下采取差异化策略,以平衡数据安全与业务便利性。
业务场景控制方式过滤策略设计原因
知识库列表分页查询调用 KnowledgeAccessFilter.applyPagePermission()✅ 严格过滤确保用户只能访问有权限的知识库
Agent关联知识库选择不调用过滤器,显示全量知识库列表❌ 不过滤保证Agent配置的完整性与灵活性,允许用户预配置未来可能授权的知识库
RAG检索调用 KnowledgeAccessFilter.filterAccessibleKnowledgeIds()✅ 严格过滤确保检索结果仅包含用户有权限的知识库数据,保障数据安全
场景说明
  1. 列表查询场景:在知识库管理页面,用户查看分页列表时,系统自动应用权限过滤,仅展示用户自己创建或被明确授权的知识库
  2. Agent关联选择场景:当用户创建或编辑Agent,在”关联知识库”选择器中,系统不进行权限过滤,允许用户选择所有知识库(包括尚未授权给自己的)。这种设计基于以下考虑:
    • Agent创建者可能提前规划未来协作场景,预先关联知识库
    • 当Agent被授权给其他用户时,只需同步授权关联的知识库,无需重新编辑Agent配置
    • 保持了配置的一致性与灵活性
  3. RAG检索场景:在Chat对话的RAG检索环节,系统严格应用权限过滤,仅从用户有访问权限的知识库中进行检索。这是数据安全的最后一道防线,确保用户无法通过对话间接获取未授权的知识库内容

3.3 其他业务表

除上述核心业务表外,系统中的其他业务表(如配置表、日志表、字典表等)不实施数据级权限控制,所有用户均可访问。 权限隔离机制:这些表的访问控制完全通过前端菜单权限(menu)实现,即用户只能看到有权限访问的菜单页面,无法访问未被授权的功能模块。 设计理由
  • 配置类、字典类数据为系统级共享资源,无需按用户隔离
  • 日志表虽包含用户操作记录,但主要通过时间范围、操作类型等维度查询,用户级隔离非必要
  • 简化权限体系,聚焦核心业务数据的安全管控

四、技术实现细节

4.1 全局拦截器实现

LcPermissionInterceptor 作为MyBatis-Plus的拦截器,通过实现 InnerInterceptor 接口,在SQL执行前自动注入权限过滤条件。 核心逻辑
public class LcPermissionInterceptor implements InnerInterceptor {
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, 
                           Object parameter, RowBounds rowBounds, 
                           ResultHandler resultHandler, BoundSql boundSql) {
        // 1. 识别需要拦截的表(aigc_app、aigc_workflow)
        // 2. 获取当前登录用户ID
        // 3. 查询用户已授权的资源ID列表
        // 4. 重写SQL,注入权限过滤条件:
        //    WHERE (creator = #{currentUserId} OR id IN (#{authorizedIds}))
    }
}
配置方式
@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加权限拦截器
        interceptor.addInnerInterceptor(new LcPermissionInterceptor());
        return interceptor;
    }
}

4.2 知识库权限过滤器

KnowledgeAccessFilter 提供显式的权限过滤方法,供业务代码在需要时调用。 核心方法
  1. 分页查询权限过滤
public class KnowledgeAccessFilter {
    public static void applyPagePermission(IPage<AigcKnowledge> page, Long userId) {
        // 查询用户可访问的知识库ID列表
        List<Long> accessibleIds = getAccessibleKnowledgeIds(userId);
        // 对分页结果进行二次过滤
        List<AigcKnowledge> filtered = page.getRecords().stream()
            .filter(kb -> kb.getCreator().equals(userId) || accessibleIds.contains(kb.getId()))
            .collect(Collectors.toList());
        page.setRecords(filtered);
    }
}
  1. RAG检索权限过滤
public class KnowledgeAccessFilter {
    public static List<String> filterAccessibleKnowledgeIds(Long userId, List<String> knowledgeIds) {
        if (CollectionUtils.isEmpty(knowledgeIds)) {
            return Collections.emptyList();
        }
        
        List<Long> accessibleIds = getAccessibleKnowledgeIds(userId);
        return knowledgeIds.stream()
            .filter(id -> accessibleIds.contains(Long.valueOf(id)))
            .collect(Collectors.toList());
    }
    
    private static List<Long> getAccessibleKnowledgeIds(Long userId) {
        // 查询aigc_data_access表,获取用户被授权的知识库ID列表
        // SELECT target_id FROM aigc_data_access 
        // WHERE user_id = #{userId} AND resource_type = 'knowledge'
    }
}
业务调用示例
@Service
public class CoreChatService {
    
    public void ragSearch(Long userId, List<String> knowledgeIds, String query) {
        // 1. 对知识库ID列表进行权限过滤
        List<String> accessibleIds = KnowledgeAccessFilter
            .filterAccessibleKnowledgeIds(userId, knowledgeIds);
        
        if (accessibleIds.isEmpty()) {
            log.warn("用户{}无可访问的知识库", userId);
            return;
        }
        
        // 2. 仅使用有权限的知识库进行检索
        List<Document> documents = vectorStore.search(query, accessibleIds);
        // ... 后续处理
    }
}

4.3 权限数据存储

权限关系通过 aigc_data_access 表存储,记录授权关系。 表结构
CREATE TABLE `aigc_data_access` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `resource_type` varchar(50) NOT NULL COMMENT '资源类型:app/workflow/knowledge',
  `resource_id` bigint NOT NULL COMMENT '资源ID',
  `user_id` bigint NOT NULL COMMENT '被授权用户ID',
  `creator` bigint NOT NULL COMMENT '授权人(资源创建者)',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '授权时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_resource_user` (`resource_type`, `resource_id`, `user_id`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据授权关系表';
数据示例
resource_typeresource_iduser_idcreator
app100120021001
knowledge300120023001
workflow500120025001
说明:表示用户1001将应用1001、知识库3001、工作流5001分别授权给了用户2002。

五、最佳实践

5.1 权限配置建议

  1. 最小权限原则:仅将必要的资源授权给必要的用户,避免过度授权带来的数据安全风险
  2. 定期审计权限:建议定期检查 aigc_data_access 表,清理过期的授权关系,特别是人员离职后的权限回收
  3. Agent与知识库同步授权:当将Agent授权给其他用户时,务必同步检查并授权关联的知识库,确保Agent功能完整可用

5.2 开发注意事项

  1. 新增核心业务表时:若该表需要按用户隔离数据,需在 LcPermissionInterceptor 中添加对应的拦截逻辑,或在业务代码中调用相应的权限过滤器
  2. 避免绕过权限控制:不要在业务代码中通过 mapper.selectList(null) 等方式绕过权限拦截器,确保所有数据访问都经过权限验证
  3. 知识库场景区分:在涉及知识库的业务逻辑中,需明确当前场景是否需要权限过滤,避免在Agent关联选择时误加过滤,或在RAG检索时漏加过滤

六、常见问题(FAQ)

Q1:为什么知识库在Agent关联时不过滤,但在RAG检索时要过滤? A:这是设计上的平衡。Agent配置时允许用户预选所有知识库,保证配置的灵活性;而实际检索时严格过滤,确保数据安全。两者互不冲突。 Q2:如何查看某个知识库被授权给了哪些用户? A:可以通过SQL查询 aigc_data_access 表:
SELECT u.username, u.real_name 
FROM aigc_data_access da 
LEFT JOIN sys_user u ON da.user_id = u.user_id 
WHERE da.resource_type = 'knowledge' AND da.resource_id = #{knowledgeId};
Q3:授权后多久生效? A:权限数据实时写入数据库,并在下一次查询时立即生效,无需重启服务或清除缓存。 Q4:撤销授权后,已使用该资源的Agent会受影响吗? A:撤销授权后,用户仍能在Agent配置中看到该资源关联,但在实际运行(如Chat对话)时,系统会自动过滤该资源,确保不会访问未授权的数据。