拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Electric Agents 权限模型实战:Principals、Grants 与授权机制全解析

Electric Agents 权限模型实战Principals、Grants 与授权机制全解析【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric导读Electric Agents 是构建在同步引擎之上的 Agent 平台其服务端通过principal调用者身份与grant权限授权双层机制对每个请求做鉴权principal 回答谁在调用grant 回答该调用者能对哪些实体类型、哪些实体实例做什么。本文以 permissions-and-principals.md 为核心骨架结合 agents-server 与 agents-runtime 的源码实现系统讲解 principal 的解析规则、实体类型/实体实例两级权限、共享角色预设、授权传播propagation、claim 写令牌以及开发环境回退帮助你为多租户 Agent 应用设计出可落地的细粒度授权方案。一、权限模型总览principal grantsElectric Agents 服务端的授权模型由两个基本概念构成Principal主体标识谁在发起请求可以是用户、Agent、服务或系统组件Grant授权决定该 principal 对实体类型entity types和实体实例entity instances可以执行哪些操作。服务端在收到请求后会从请求头解析出 principal再结合存储的 grants 判断当前操作是否被允许。从 permissions.ts 的实现可以看到实体与实体类型两条鉴权路径结构对称先检查是否为内置系统 principal内置系统主体可绕过权限检查isPermissionBypassPrincipal然后剪除过期授权pruneExpiredPermissionGrants再进行内置规则判定最后交给可选的 authorization hook 做二次决策。二、Principals身份如何传递与解析2.1 请求头与 key 格式调用方通过Electric-Principal请求头传递一个 principal key其形状为kind:id支持的 principal 类型kind为user、agent、service和system。例如user:sam会被服务端转换为规范的 principal URL/principal/user%3Asam。在 principal.ts 中parsePrincipalKey完整实现了这一解析逻辑以第一个:切分 kind 与 idkind 必须在user、agent、service、system集合内否则抛Invalid principal kindid 不能为空、不能包含/否则抛Invalid principal id最终用encodeURIComponent对kind:id整体编码拼出规范 URL/principal/encoded。export function parsePrincipalKey(input: string): Principal { const colon input.indexOf(:) if (colon 0) throw new Error(Invalid principal identifier) const kind input.slice(0, colon) as PrincipalKind const id input.slice(colon 1) if (!PRINCIPAL_KINDS.has(kind)) throw new Error(Invalid principal kind) if (!id || id.includes(/)) throw new Error(Invalid principal id) const key ${kind}:${id} return { kind, id, key, url: /principal/${encodeURIComponent(key)} } }此外parsePrincipalInputprincipal.ts同时兼容两种输入既能解析/principal/user%3Asam形式的 URL也能解析user:sam形式的裸 key服务端据此把任意格式的请求头值规范化为{ kind, id, key, url }四元组。2.2 客户端如何携带 principal在 TypeScript 客户端中通过createRuntimeServerClient的principalKey选项声明调用者身份。运行时客户端在每次请求发出前会把该值写入Electric-Principal请求头见 runtime-server-client.tsimport { createRuntimeServerClient } from electric-ax/agents-runtime const client createRuntimeServerClient({ baseUrl: http://localhost:4437, principalKey: user:sam, })对应的底层常量ELECTRIC_PRINCIPAL_HEADER electric-principal定义在 principal.ts服务端通过getPrincipalFromRequest从请求中读取该头并解析。CLI 场景下同样的值可通过环境变量传递ELECTRIC_AGENTS_PRINCIPALuser:sam electric agents ps对于需要额外认证头的部署服务端还支持通过ELECTRIC_AGENTS_SERVER_HEADERS环境变量或客户端serverHeaders选项注入附加请求头具体取决于宿主环境。这意味着在网关层完成 OAuth 等外部认证后可以把解析出的身份以附加头形式透传给 agents 服务端实现网关认证 服务端授权的解耦。2.3 内置系统 principal 与鉴权旁路源码中还定义了三个内置系统 principalframework、auth-sync、dev-localprincipal.ts。isBuiltInSystemPrincipalUrl会识别它们permissions.ts 中isPermissionBypassPrincipal对这类内置系统主体直接放行——这是框架内部组件如认证同步、开发回退操作实体的机制普通业务代码不应依赖它。开发环境的回退 principal 即system:dev-local由getDevPrincipal()生成见下文开发环境回退一节。三、实体类型权限Entity type permissions3.1 两级类型级权限实体类型级 grant 控制谁可以 spawn 或管理该类型的实体包含两种权限权限允许的操作spawn生成spawn该类型的实体manage管理该实体类型并作为更宽泛的类型级权限从类型定义看类型级授权同样支持expires_at过期时间见 types.tsexport type EntityTypePermissionGrantDefinition { subject_kind: principal | principal_kind subject_value: string permission: spawn | manage expires_at?: string }3.2 在实体定义中声明初始类型授权类型级授权可在实体定义entity definition中通过permissionGrants声明。实体定义的完整结构见 types.ts其中permissionGrants?: ReadonlyArrayEntityTypePermissionGrantDefinition即本节字段registry.define(worker, { description: Internal worker, permissionGrants: [ { subject_kind: principal_kind, subject_value: user, permission: spawn, }, ], async handler(ctx) { // ... }, })subject_kind支持两种取值principal精确匹配某一个 principal按 URL 或 keyprincipal_kind匹配某一 kind 下的所有principal如上面例子中所有user均可 spawnworker实体。3.3 内置实体类型的默认授权仓库内置的 Horton 与 Worker 注册项默认对所有userprincipal 授予spawn和manage两种类型级权限。这样本地或托管环境中的 user principal 可以创建内置会话并能读取创建界面所需的类型元数据。自定义实体类型则应当自行设计permissionGrants不要默认向所有用户开放manage。服务端判定类型级访问的入口在 permissions.ts 的canAccessEntityType它调用hasEntityTypePermission检查内置授权再交给 authorization hook 复核。四、实体权限Entity permissions4.1 八种实体级权限实体级 grant 控制对已存在实体实例的访问权限集更细权限允许的操作read读取实体元数据与流write发送消息、写入实体所属资源delete删除或终止kill实体signal发送生命周期信号fork从实体历史中 fork 出新实体schedule创建、更新或删除调度schedulespawn从该实体 spawn 子实体manage管理 grants并作为更宽泛的实体级权限注意manage是实体级超集权限拥有它即隐含了对该实体其他操作的管控能力因此它也是后续委托delegation语义的基础。实体级访问判定入口为 permissions.ts 的canAccessEntity。4.2 通过 spawn 路由携带初始实体授权服务端 spawn 路由可以在创建实体时直接声明初始实体 grants。下面的例子用原生fetch直接调用 HTTP 接口在创建support-ticket-42的同时授予user:sam对该实体的read权限await fetch(http://localhost:4437/_electric/entities/assistant/support-ticket-42, { method: PUT, headers: { content-type: application/json, electric-principal: user:sam, }, body: JSON.stringify({ grants: [ { subject_kind: principal, subject_value: /principal/user%3Asam, permission: read, }, ], }), })要点subject_kind: principal表示精确授予某一 principalsubject_value使用规范 principal URL/principal/user%3Asam与 principal.ts 的principalUrl输出一致请求头electric-principal: user:sam用于声明创建者身份创建者默认拥有该实体见 permissions.ts 中entity.created_by ctx.principal.url的内置判定。4.3 从父实体 spawn 时的委托语义当从父实体parentspawn 子实体、并希望把权限一并委托出去时较宽的委托行为要求调用者拥有父实体的manage权限。文档明确列举了这类需要manage的宽委托场景授予manage这类超集权限使用principal_kind形式的授权面向某 kind 全体后代传播descendant propagationcopy_to_children子实体拷贝授权。也就是说manage不仅是操作权限更是授权管理权的载体——它决定了谁有权把权限体系继续往下分发。五、共享角色Sharing roles服务端底层存储的是细粒度 grants但面向用户的共享 UI 会呈现为更易理解的角色预设角色对应 grantsviewread、forkchatread、write、signal、fork、schedule、spawnmanagemanage、delete这三个角色是实体级 grants 的预设组合它们并不会改变底层权限模型本身部署方仍可直接授予单个权限实现比角色更细的控制。值得注意的设计点是服务端通过 Electric shapes同步形状向共享 UI 暴露 principal 与 effective-permission生效权限数据但授权判定始终发生在服务端——UI 上看到的可见性是由物化materialized后的生效权限推导出来的客户端拿到的是能看什么的视图而能不能做由服务端每个请求逐一校验。这也呼应了项目基于同步构建的定位权限数据可同步到 UI但授权决策不信任客户端。六、授权传播Grant propagation实体 grants 支持传播选项用于控制授权在实体树中的传递范围{ subject_kind: principal, subject_value: /principal/user%3Asam, permission: read, propagation: descendants, copy_to_children: true, }各选项语义propagation: self授权仅作用于实体自身propagation: descendants授权沿后代实体链传递覆盖该实体所有后代copy_to_children: true在 spawn 子实体时把该授权拷贝给子实体expires_at为授权设置过期时间戳到期自动失效。服务端在授权判定前会调用pruneExpiredPermissionGrants清理已过期的授权见 permissions.ts保证expires_at语义在鉴权路径上真正生效而不是只停留在存储层。七、Claim 作用域的写令牌Claim-scoped write tokens7.1 为什么需要写令牌实体的一些底层写操作由claim 作用域写令牌保护。所谓 claim 是指当前正在执行的上下文例如一次 handler 唤醒、一次消息处理。Handler API 如ctx.setTag()、ctx.deleteTag()内部已经携带了当前激活的 claim 上下文因此 handler 内调用无需额外令牌而外部客户端通常不应直接改写实体所属状态正确做法是向实体发送消息让实体在自己的 claim 上下文里完成状态变更。7.2 自定义令牌传输头如果宿主环境占用了Authorization头用于服务端认证例如Bearer serverToken就需要通过writeTokenHeader或claimTokenHeader为写令牌指定独立的传输通道const client createRuntimeServerClient({ baseUrl: http://localhost:4437, headers: { authorization: Bearer ${serverToken} }, writeTokenHeader: electric-claim-token, })在运行时客户端的实现中runtime-server-client.tsapplyTokenHeader会按配置分发令牌writeTokenHeader authorization默认值且头未被占用时写入Authorization: Bearer tokenwriteTokenHeader electric-claim-token时写入electric-claim-token头取值为both时两个位置同时写入。类型定义runtime-server-client.ts中writeTokenHeader?: ClaimTokenHeader与principalKey?: string并列说明令牌与身份是两套独立的请求元数据principal 负责你是谁claim token 负责你正代表哪个 claim 在写。八、开发环境回退Development fallback本地开发服务器支持开发用 principal 回退当请求未携带Electric-Principal头时服务端会回退到system:dev-local这一内置开发主体见 principal.ts 的getDevPrincipal。需要强调的是这只是本地开发便利性设计生产部署必须对每个请求完成真实身份认证并为每个请求显式提供Electric-Principal头system:dev-local属于内置系统 principal会被isPermissionBypassPrincipal识别为可旁路鉴权的主体见 permissions.ts因此绝不能在非受信环境开启该回退否则等于绕过了全部授权检查。九、授权链路一图流从请求到决策综合上述源码路径一个带身份请求的完整授权链路可以归纳为客户端通过principalKey或 CLI 的ELECTRIC_AGENTS_PRINCIPAL把user:sam写入Electric-Principal头服务端getPrincipalFromRequest读取请求头parsePrincipalInput将其规范化为/principal/user%3AsamURLprincipal.ts实体/类型路由调用canAccessEntity/canAccessEntityTypepermissions.ts内置系统主体直接放行否则先pruneExpiredPermissionGrants清理过期授权内置判定实体创建者created_by默认有权限否则查hasEntityPermission/hasEntityTypePermission匹配存储的 grants含传播语义如有自定义 authorization hook再以builtInAllowed为输入做最终决策。结语Electric Agents 的权限体系可以用一句话概括principal 定身份、grant 定动作、manage 管委托、claim token 守写入、dev fallback 只属于开发环境。从 permissions-and-principals.md 的配置指南到 principal.ts、permissions.ts 与 runtime-server-client.ts 的实现这套模型覆盖了从谁能建实体到谁能改状态、谁能继续授权的完整链路。在设计多用户 Agent 应用时建议自定义实体类型显式声明permissionGrants敏感操作一律通过发送消息而非外部直写利用propagation与copy_to_children维护实体树授权生产环境关闭开发回退并强制每个请求携带显式 principal。【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门