编辑 | blame | 历史 | 原始文档

工业智能体授权设计:菜单、按钮与数据范围

2026-10-21,设计稿。适用于运营场景、工作文件补录、定时任务、审批恢复和结果导出。模型依据服务端提供的可用能力规划任务;最终授权由 Java 服务端执行。

1. 授权原则与项目依据

用户通过智能体访问业务时,拥有的能力不得超过其通过正常业务系统获准使用的能力。工具授权综合判断模块/菜单授权、操作权限码、对象数据范围、字段策略、业务状态和动作审批要求。任意一项不满足,禁止相应调用。

已核对的代码基础:

  • AuthController.getPermissionInfo() 获取当前用户、启用角色和过滤禁用项后的菜单列表。
  • PermissionServiceImpl.hasAnyPermissions() 与 getDeptDataPermission() 提供功能权限与部门范围基础能力。
  • 业务 Controller 使用 @PreAuthorize 检查权限码,例如合同的 crm:contract:query/create/update/delete/import/export。
  • 数据权限框架在查询侧应用规则;CRM 还有 CrmPermissionAspect 的对象级权限与公海等领域规则;售后有独立 AfterSalePermissionService。

这些规则组合方式由现有 Java 权限服务和业务服务决定,Python 不自行用角色名称或部门 ID 推算“应该有权限”。上面的代码核对不代表每个模块均已完成数据权限审计,接入前需验证列表、详情、聚合与写入的一致性。

2. 菜单、按钮、数据与字段的关系

层次 作用 Agent 的行为
菜单/模块授权 用户获准进入的业务域 服务端能力目录关联 menu_id/module;无授权不开放该域工具
按钮/操作权限 查询、新增、修改、删除、导入、导出、提交等 精确映射工具到所需权限表达式,不用“有菜单”代替操作权限
数据范围 本人、部门、下级部门、自定义及领域对象授权 查询时在服务端约束;给定 ID 也要对象校验,不能只过滤列表
字段权限 成本、底价、薪酬、账号、联系方式等敏感字段 在数据进入模型之前过滤;若现有系统未统一提供,新增字段策略
状态/审批 已关闭、审批中、已执行等业务限制 有按钮权限仍需校验状态;审批资格与执行资格分别核验

菜单的前端隐藏属性、页面路由可见性和服务端授权不同。隐藏详情页不应一律视为未授权;以服务端实际授权关系和能力映射为准。菜单授权不完整、无对应菜单的跨模块服务能力,必须显式登记,不能从前端传来的菜单树判断。

多角色的功能权限与数据范围合并沿用现有系统语义;不能对全部角色简单求交集导致误拒,也不能把不同业务对象上的授权随意求并导致扩大范围。Agent 动作策略可以收紧业务权限,不得将其放宽。

3. 服务端能力目录与 LangGraph 路径

拟新增 Java AgentAuthorizationService:生成能力目录,执行工具/对象/字段判定,并记录授权决策。拟提供 capabilities 和 check-action 内部接口;前者用于规划,后者及业务服务用于实际调用。

验证当前用户/受控委托
→ Java 计算可用能力与 policy_revision
→ LangGraph 只绑定当前场景的已授权工具
→ 模型提出结构化计划
→ 代码检查计划工具与参数范围
→ Java 每次重新鉴权并执行带范围的业务查询/命令
→ 过滤字段后交给模型
→ 结果查看、附件下载、导出与发送时再次检查

能力目录示意:

{
  "policy_revision": "server-generated-version",
  "capabilities": [{
    "tool": "crm.contract.read",
    "module": "crm",
    "operation": "query",
    "scope_summary": "仅当前用户可见合同",
    "allowed_fields": ["code", "customer_name", "delivery_date"],
    "can_execute": true
  }]
}

目录是短期规划提示,不是可长期使用的授权凭证。服务端保存真实权限表达式与数据规则,不必把完整角色配置、可访问 ID 列表或内部 SQL 发给模型。字段白名单按具体对象与用户策略进一步收紧。

LangGraph 在入口增加 load_capabilities,在计划后增加 authorize_plan,工具封装统一 authorize_and_invoke。权限不足走 access_limited 分支,向用户说明可执行部分和缺少的操作权限,不泄露无权对象的名称、数量或内容。

4. Java Bridge 的强制检查

Bridge 直接调用 Service 时,原 Controller 上的 @PreAuthorize 不会因此自动执行,必须显式检查对应功能权限;对象规则也必须经过实际生效的 Service/AOP/查询路径。不得为跨模块方便使用全局管理员身份、executeIgnore 或关闭数据过滤来代查。

源身份由 Java 鉴别并签发短时委托上下文,包含用户、租户、audience、有效期与允许用途。工具参数中的 user_id/dept_id/owner_id 不具有授权效力。后台线程执行时建立正确的服务端身份上下文并在结束时清理,防止线程复用串身份。

查询、详情、关联查询、聚合、搜索建议、文件检索都要执行相同范围规则;禁止“先查全量,模型再筛选”。更新/删除除了权限码,还校验目标对象;新增校验可指定的部门、负责人、仓库、客户等关联对象,不能借新增把数据挂到无权部门。

5. 跨模块分析与输出控制

例如销售有合同查询权限但没有采购价格权限:可以在已授权范围内分析合同;不能把采购单明细和价格提供给模型。如果企业希望销售了解交付能力,新增经过授权的“交期评估摘要”能力,由服务端限制输出字段和来源范围,而非自动继承采购明细权限。

跨模块任务逐节点授权,必需数据无权限时标注“当前授权范围不足以完成评估”,不得把不可见部分当作不存在或 0。结果注明“当前可见范围”,不得宣称是全企业统计。若提供跨范围汇总,需有独立聚合授权及输出策略,不能借汇总推断隐藏客户或敏感金额。

权限过滤同样覆盖证据链接、引用标题、附件预览、SSE、报告下载、分享与通知。导出需要对应导出授权;查询权限不自动包含导出权限。发送结果同时检查发起人发送权限及接收人的可见范围。原始来源的权限不会因为做成摘要而消失。

6. 文件补录的权限规则

上传权限、查看文件权限、匹配系统数据权限、建立主数据权限、导入业务权限和更新既有数据权限分别判断。用户上传了文件,不代表获准查询文件中提及的所有系统记录,也不代表获准导入其中全部数据。

  • 实体匹配只返回可见候选;发现全局唯一键冲突但目标不可见时,返回通用冲突和受控处理入口,不透露目标记录信息。
  • 导入动作采用经过评审的权限组合:例如需模块导入权限及相应创建/更新能力,具体与现有导入 Service 语义对齐;不能擅自假设一个 import 权限涵盖全部操作。
  • 批次中有权和无权记录分别标识;无权行阻断其依赖链。明确审批计划后才允许独立有权分组继续执行。
  • 补录主数据缺失时,无新增权限的用户只能提出申请或暂存候选,不自动新建客户、物料、仓库。
  • 负责人/部门归属、迁移历史状态、期初余额等涉及额外权限,逐字段/动作校验。dry-run、提交和回读都重新授权。
  • 原始文件、候选、问题清单、人工修订和导入报告设批次 ACL;协作人员看到的内容按其权限裁剪,不能因参与批次就获准查看所有薪酬或成本。

7. 审批恢复、定时任务与权限变化

审批人有审批权,不代表发起人自动获得执行权。默认执行要求发起人的当前授权仍有效;如业务允许由独立执行主体接管,必须记录明确的主体切换、委托范围和审批依据,不能默默使用审批人或管理员身份。

角色撤销、账号禁用、离职交接、对象归属变化、菜单禁用时,更新授权版本并失效能力缓存。挂起图恢复时重新加载权限;准备好的方案不保留旧授权。执行时仍检查最新权限,避免只依赖失效通知。

个人定时任务使用明确的受控委托,用户停用/撤权后暂停。企业巡检使用专门服务主体和批准的数据范围;向个人推送前按接收人权限裁剪。个人对话不可借企业巡检主体扩大查询范围。

缓存按租户、主体、权限版本、对象/字段范围隔离;检查点和产物不直接面向前端。权限收紧后,再次读取旧结果、恢复会话或重建模型上下文时重新授权,必要时遮蔽或重新生成。已向用户展示过的信息无法撤回,但系统不能继续返回已撤权内容。

8. 审计与验收

每次授权决策记录主体、委托主体、tool/action、对象引用、权限版本、决策、原因码、task_id、approval_id(适用时)。拒绝日志避免记录完整敏感字段。前端原因区分无操作权限、数据范围不足、状态不允许、审批缺失与授权过期;不得泄露无权对象存在性。

验收必须包含:有菜单无查询按钮;可查不可改;可查不可导出;本人数据越界详情 ID;跨部门聚合;CRM 只读/读写/负责人;售后对象权限;新增时指定无权负责人;导入含无权关联对象;审批等待中撤权;旧检查点与缓存泄漏;服务账号巡检结果推送;字段脱敏;Bridge 绕过 Controller 的防护。

本次为方案补充,未改变现有权限代码。实施时逐模块登记“菜单绑定、工具权限表达式、对象规则、字段策略、状态规则、审批门槛”,未登记或核验失败的能力默认关闭。