ObjectOS
配置权限

字段级安全

隐藏或锁定单个字段 —— 授予语义、服务端强制执行,以及 FLS 在表单、视图和 API 中的行为。

字段级安全(FLS)控制单个字段的可见性与可编辑性,作用于对象权限和记录访问已经允许用户触达该记录之后。它是实现"支持人员能看到客户,但看不到其 annual_revenue"和"销售代表能读外部 id 但永远不能改"的那一层。

FLS 规则存在权限集中——本页比那里的字段安全附录更深入地讲解授予语义与强制执行。

字段权限授予

字段权限以 <object>.<field> 为键,使用 readable / editable

fields: {
  // 只读:可见但不可编辑
  'account.annual_revenue': { readable: true, editable: false },
  'account.description': { readable: true, editable: true },
  // 隐藏:完全不可见
  'account.ssn': { readable: false, editable: false },
  'opportunity.amount': { readable: true, editable: true },
  'opportunity.probability': { readable: true, editable: false },
}

两个标志产生三种状态:

状态规则效果
隐藏{ readable: false, editable: false }字段完全不可见——从每个响应中剥离
只读{ readable: true, editable: false }字段会返回,但对它的写入会被拒绝
可编辑{ readable: true, editable: true }字段可见且可写

字段权限键务必写成带对象限定的形式(crm_lead.budget,而不是 budget)——自 ObjectStack 14.4 起,security-fls-unqualified-key lint 会在编译时拒绝裸键,因为它们会静默地匹配不到任何东西。

授予如何合并

FLS 使用默认可见(黑名单)语义:没有显式规则的字段原样通过——既可读可写。权限集只约束它显式列出的字段。

字段授予在用户的多个权限集之间按最宽松方式取并集:一个权限集的 readable: true 会压过另一个权限集的 false。在减法式屏蔽层落地之前(已保留为 ADR-0066 ⑧),{ readable: false } 规则只有在用户持有的其他任何权限集都没有声明该字段 readable: true 时才会遮蔽它。实际影响:

  • 保护敏感字段的方式是在需要它们的权限集中授予——绝不要指望某个权限集里的 false 规则去覆盖别处的 true
  • 把出现在广泛授予的对象上的敏感字段视为评审警讯。

已声明的规则本身以 fail-closed 方式强制执行:被遮蔽的字段在读取时被剥离,对不可编辑字段的写入会抛错。

API 中的强制执行

SecurityPlugin 中间件在服务端强制执行字段规则,与请求来路无关——REST、ObjectQL 或任何其他路径。不存在通过更底层 API 的后门。

读取时——find / findOne 的结果在响应离开引擎之前,会从每条记录中剥离不可读字段。

写入时——insert / update 请求在操作到达驱动之前被检查。如果请求体包含任何调用者无权编辑的字段,引擎抛出 PermissionDeniedError(HTTP 403),并附上违规字段名:

{
  "error": {
    "code": "PERMISSION_DENIED",
    "message": "[Security] Field write denied: not permitted to edit [salary, ssn] on 'employee'",
    "details": {
      "operation": "insert",
      "object": "employee",
      "forbiddenFields": ["salary", "ssn"]
    }
  }
}

**为什么抛错而不是静默剥离?**静默剥离对诚实的客户端隐藏了安全边界(它们的更新"存不上"却不知道为什么),同时对探测型客户端也不给任何信号。抛错让边界在两个方向上都可观测——正当的 UI 得到可据以修复的错误;探测型客户端学不到任何它本来推断不出的东西。

另外两个强制执行细节:

  • 批量插入逐行检查;任意一行中出现一个违规字段,整个批次会被原子性拒绝。
  • 系统操作ExecutionContext { isSystem: true })完全绕过该检查——用于迁移、种子数据加载和审计日志写入。

FLS 在表单和视图中

生成的表单和内联表格会在 UI 中隐藏不可编辑字段——但那只是 UX 层。上文的服务端检查才是事实来源,因此行为在所有地方保持一致:

界面隐藏字段只读字段
记录表单 / 内联表格不渲染渲染但无可编辑控件;直接尝试写入会被 403 拒绝
列表视图、相关列表、导出列值从响应中剥离值正常显示
REST / ObjectQL从结果中剥离读取时返回;写入抛出带 forbiddenFieldsPERMISSION_DENIED
MCP / AI Agent剥离——Agent 以调用用户身份运行与 REST 相同

由于读取是剥离而不是报错,隐藏字段对该用户来说就像不存在一样——这正是目的所在。

验证与评审 FLS

  • 按判定、在运行时——解释引擎会连同其他每一层一起报告 FLS 层的判定结果,并点名起作用的权限集。当用户反馈字段"不见了"时用它。
  • 按变更、在构建时——如果你的应用启用了访问矩阵快照门禁,os compile 会把推导出的(权限集 × 对象)能力矩阵与已提交的 access-matrix.json 做 diff,并在漂移时失败,让能力变更以可评审的语义 diff 形式随 Pull Request 流转:
os compile --update-access-matrix

当字段承载敏感数据时,默认选隐藏而不是只读——只读仍会把值泄漏进响应和日志。把字段规则打包进匹配真实职能的权限集,并为合规场景配套审计日志留存。更多编写模式:权限集

下一步

任务页面
在权限集中编写字段规则权限集
控制哪些行完全可触达记录访问
纵览整套分层模型权限
验证某个用户的访问权限权限分配
检查 AI Agent 能读到什么接入 AI 工具(MCP)

On this page