Skip to content

[待开发]建立认证器协议驱动的公开认证区块与自行注册 #1444

Description

@JAVA-LW

Related: #1154, #1155, #1156, #1162, #1182, #1185
Canonical code-block runtime / API contract: #1393

Issue 元数据

  • 计划类型:Single Issue
  • 分级:grade:g4
  • 任务形态:hybrid-foundation
  • 标签:plan:singlegrade:g4phase:discussiontype:featurearea:backendarea:frontendarea:apiarea:settingsarea:schema-uiarea:runtimecontractsecurityuser-datamigrationneeds-backendneeds-frontendneeds-qa

预期结果

把公开认证页收敛为“认证器实例选择壳层 + 认证器拥有的完整代码区块”:

  • 每个已启用认证器实例持久化一个完整 public_ui_block,它同时表达该认证器的登录、注册、扫码、跳转或其他公开认证交互,是该认证器公开 UI 的唯一真值。
  • Core /sign-in 不再生成账号密码表单,也不按 auth_type 拼装登录/注册 UI;它只获取可用认证器、选择实例、注入后端公开变量与 canonical Block context,并复用 canonical 代码区块组件渲染。
  • 只有一个认证器时直接显示其 Block,不显示选择器;多个认证器时显示一列实例按钮并渲染当前实例 Block;没有可用实例时显示明确不可用状态,不回退到另一份 Core 表单。
  • 后端认证插件可以随 provider contribution 注册后台 config_schema、默认完整代码区块、公开变量投影和 public Auth API operation;安装后端插件不需要修改或重新发布 Core 前端。
  • password-local 默认区块同时承载登录与自行注册。self_registration_enabled 由后端认证器配置决定,仅作为 public_variables 注入 Block 供其决定是否展示注册入口。
  • 浏览器修改 Block、变量或请求不能开启后端能力:注册动作必须重新读取持久化认证器配置,配置未开放时直接拒绝。
  • 插件默认区块只在创建实例或一次性补齐历史空值时注入;插件升级不得静默覆盖认证器已经保存的用户区块。

最终数据流:

Auth Provider contribution
  -> config_schema + default_public_ui_block
  -> public variable projection + public Auth API operations
  -> Authenticator instance persists public_ui_block and private config
  -> GET /api/public/auth/login-instances returns public projection
  -> Core selects one instance and mounts the shared Block host
  -> Block reads immutable public inputs and invokes provider APIs through canonical ctx.api
  -> Auth Center reloads config, authorizes the action, then owns user/identity/session writes

现状与证据

已确认事实

待验证假设

  • password-local 自行注册可以复用现有用户/成员创建、密码策略与 user_auth_identities 写入入口,在同一后端事务内完成,而不新增旁路 repository write。
  • 若公开注册必须创建 workspace membership,默认归属、默认角色、激活/验证策略必须来自后端显式配置;请求体不得携带可生效的角色、owner 或权限。若当前没有安全的 canonical provisioning policy,进入实现前先在本 Issue 补齐该字段与默认值。
  • [Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 最终合入的代码区块 program、inputs 和 ctx.api contract 能在未登录页面由 Auth host adapter 复用;若最终合同发生实质变化,只调整共享 adapter,不改变“一个完整 Block 是 UI 唯一真值”的产品边界。

范围、权限与边界

范围内

  • 为 HostExtension Auth Provider contribution 增加并校验:后台 config_schemadefault_public_ui_block、后端公开变量投影、可供该 Block 通过 ctx.api 调用的 public Auth API operations。
  • 在认证器领域模型、repository、migration、settings DTO/API 中增加一等 public_ui_block,其值直接使用 canonical 完整代码区块 program/descriptor,不复制出 Auth 专用 AST。
  • 让认证器后台 schema-driven 配置表单能够展示、编辑、校验和保存 public_ui_block;该控件复用已有代码区块编辑/预览组件,不把源码复制进 options 形成第二真值。
  • 扩展 GET /api/public/auth/login-instances 的职责单一 public projection:只返回已启用实例的公开元数据、完整 public_ui_block 和后端生成的 public_variables;不返回 raw options、后台 schema、secret 或第二份接口目录。
  • 抽取或复用 feature-neutral 的代码区块 mount/render 组件,并实现 Auth host adapter:使用 canonical Block context/inputs/ctx.api contract 注入认证器上下文,不依赖 Frontstage page、page document 或 block-code API。
  • 改造 /sign-in 的单实例、多实例、零实例、加载失败和区块运行失败交互;删除 Core 自有账号密码登录表单以及按认证类型解释 UI 的分支。
  • password-local 提供默认完整 Block,覆盖现有登录与可选自行注册;增加自行注册 public Auth API、后端 command、事务写入、错误语义与审计。
  • 历史内置认证器回填默认 Block;self_registration_enabled 安全默认 false。历史非空用户 Block 不覆盖。
  • 覆盖插件首次安装、创建实例、复制实例、升级插件、禁用实例和删除实例时的 Block 生命周期。

非目标

  • 不建立 Auth 专用 TSX 方言、Schema UI 公开登录表单、受限能力子集、认证类型 renderer 或另一套 Block runtime。
  • 不让 Core 根据 self_registration_enabled 等变量生成、隐藏或拼接任何认证控件;变量的显示解释只属于认证器 Block。
  • 不让公开登录页读取 Frontstage page/document/block-code 资源,也不为了认证 UI 创建隐藏 Frontstage 页面。
  • 不在本 Issue 接入一个真实 OIDC/SAML/短信/企业微信插件;协议和 fixture 必须证明后端插件可贡献不同 UI/API,但具体 provider 另开 Issue。
  • 不允许认证插件绕过 Auth Center 直接写 users、user identities、sessions、roles 或 workspace memberships。
  • 不在插件升级时自动“同步最新版模板”;如未来需要手动比较或重置到新模板,另行确认其覆盖语义。

已授权动作

  • 当前仅授权创建和完善本线上 Single Issue;不授权在本轮修改产品代码、执行 migration 或发布。
  • 用户确认本 Issue 正文并将其推进到 phase:ready 后,授权在既定范围内完成前后端、migration、fixture、测试和 QA 闭环。

需要额外确认的动作

  • 若现有后端没有可复用的安全注册 provisioning policy,需要用户确认新用户默认归属、角色、激活和验证语义后才能进入实现。
  • 覆盖任意非空历史 public_ui_block、删除历史认证/身份数据、放宽现有代码区块 capability/security contract,必须另行确认。

方案结论

采用方向与关键取舍

  • 采用“协议驱动的单一组合合同”,不采用“简单表单走 schema-ui、复杂认证走 TSX”或“Core 默认表单 + 插件 TSX”两套维护模式。
  • 一个认证器实例只有一个完整 public_ui_block。登录与注册可以同时在该 Block 内,也可以由 Block 自己切换步骤;Core 不拥有第二份登录/注册 UI。
  • authenticators.public_ui_block 是公开 UI 内容真值;认证器私有配置是动作许可真值;public_variables 是后端从配置生成的只读公开投影,不是另一份持久化配置。
  • Provider contribution 的 default_public_ui_block 只是实例初始化种子,不是运行时覆盖真值。新实例复制当前默认值;既有实例保留保存值。
  • Auth host adapter 复用 canonical Block program、renderer、module、permission 与 capability contract。它只负责构造未登录认证上下文并提供 canonical ctx.api transport,不解释认证业务字段。
  • Block 源码复用 [Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 最终 ctx.api.<method>(path, request) 合同调用 provider 注册的 public Auth API;后端 route/OpenAPI 和 Auth Center/Provider registry 是接口与授权真值。不得新增 ctx.auth.*、接口 descriptor 目录、持久化 binding 或另一套 dispatch 体系。
  • password-localself_registration_enabled=false 是安全默认。Block 可以根据公开变量隐藏注册入口,但后端拒绝才是安全保证。

建议合同形状

字段名以领域语义为准;实现不得为了前端展示另起别名:

AuthenticatorProviderContribution
  config_schema
  default_public_ui_block          // canonical Block program/descriptor
  public_variable_projection       // server-side projection, never raw options
  public_auth_operations           // backend routes/OpenAPI; Auth Center mediated

AuthenticatorRecord
  id / auth_type / title / enabled / sort_order
  private config
  public_ui_block                  // persisted user-owned UI truth

PublicLoginInstance
  id / auth_type / title / sort_order
  public_ui_block
  public_variables

Auth Block inputs
  authenticator_id
  public_variables
  locale/theme and other canonical Block context

Auth Block API
  ctx.api.<method>(path, request)   // canonical Block contract, no Auth-specific fork

auth_type 可以作为公开元数据返回,但 Core 不得用它选择组件、字段或提交流程。

复杂度归属

  • Provider-specific UI、公开变量与 public API 属于后端 Auth Provider contribution / authenticator instance。
  • 用户、身份绑定、session、注册许可、角色/归属约束和审计属于 Auth Center。
  • 源码执行、inputs、ctx.api、module 与 renderer 属于共享代码区块协议/runtime。
  • /sign-in 只拥有认证器选择、加载态、错误边界和共享 Block mount,不拥有认证业务表单。

Domain Matrix

Object / behavior Owner Source of truth Persisted User editable Public/runtime contract Historical impact Unacceptable failure mode
default_public_ui_block Auth Provider contribution installed provider package provider artifact no initialization only new/missing instances plugin upgrade overwrites a saved instance Block
authenticators.public_ui_block Auth Center / authenticator instance authenticator record yes yes, via settings yes password-local backfill Core/Frontstage owns another UI copy or migration overwrites non-empty content
private authenticator config Auth Center/provider persisted backend config yes permitted fields only no raw public exposure add safe registration default browser variable/request becomes permission truth
public_variables provider server-side projection current persisted config no second truth no yes, read-only none raw options/secret/schema leaks or frontend invents compatibility values
public Auth API operations provider registry + Auth Center registered backend route/OpenAPI registry/runtime no yes none plugin route bypasses Auth Center writes or trusts browser state as authorization
selected authenticator Core login shell public ordered instance list page state only user selects yes none Core branches by auth type or submits against a different instance
self-registered user/identity/session Auth Center domain service + repository transaction yes public input under policy yes new user data disabled registration succeeds, duplicate partial writes, client grants itself role/owner

验收点账本

编号 可观察结果 证据 结算阶段
AC-001 一个 fixture Auth Provider 只安装后端 contribution,即可注册 config schema、默认完整 Block、公开变量和 public Auth API;非法/重复/缺字段 contribution fail closed plugin-framework/domain/control-plane contract tests 本地 + QA
AC-002 认证器实例持久化 canonical public_ui_block,后台 schema-driven 表单可编辑、校验、保存并重开;私有配置与公开 Block 无双写 migration/repository/route tests + settings Vitest 本地 + QA
AC-003 public login-instances 只投影已启用实例的公开字段、Block 和变量,不泄漏 raw options、secret、后台 schema 或第二份接口目录 public API allow/deny fixture + response snapshot 本地 + QA
AC-004 一个实例时直接显示 Block;多个实例时显示一列按钮并切换对应 Block;零实例/API 失败时显示正式错误状态且没有 Core 表单 fallback SignInPage Vitest + desktop/390px browser evidence QA + 用户验收
AC-005 Auth 页面与 Frontstage 消费同一 canonical Block component/runtime/module/capability contract,仅 host adapter 不同;仓库中不存在 Auth 专用源码方言、renderer 或 runtime fork package build/tests + architecture review QA
AC-006 password-local 默认 Block 在同一 Block 内完成登录,并只在后端注入 self_registration_enabled=true 时展示自行注册交互 Block/runtime fixture + public browser flow QA + 用户验收
AC-007 即使浏览器把变量改为 true、篡改 authenticator_id 或直接调用注册 API,后端在持久化配置为 false、实例禁用或 route/provider 不匹配时均拒绝且不产生用户/identity/session backend negative route/service/repository tests 本地 + QA
AC-008 注册开放时通过 Auth Center 原子创建合法用户与 password-local identity,遵守密码/唯一性/provisioning policy,不接受客户端角色、owner 或权限提升 transaction/concurrency/duplicate/permission tests + audit assertion 本地 + QA + CI-beta
AC-009 历史 password-local 实例得到默认 Block 且注册默认关闭;迁移前后 id/身份绑定不变,已有非空 Block 不被覆盖 migration fixture + preflight count + rollback rehearsal QA + CI-beta
AC-010 新建实例获取当前插件默认 Block;复制实例复制当前保存 Block;插件升级后已有实例内容逐字节保持不变 install/create/copy/upgrade lifecycle tests 本地 + QA
AC-011 无效或运行失败的 Block 被隔离到当前认证器错误边界;多实例选择仍可切换,系统不静默执行另一份登录表单 runtime/error-boundary Vitest + browser evidence QA

验证与资源边界

  • 实现前使用 test-driven-development 固定有限 acceptance matrix:单/多/零实例、登录、注册开/关、变量伪造、实例禁用、secret 投影、无效 Block、历史回填、插件升级不覆盖。
  • 后端最小证据:plugin contribution contract、domain/repository、Auth Center settings/public routes、注册 command/transaction、权限与审计的定向 Rust 测试;同一 worktree 同时只运行一条 Cargo 命令。
  • 前端最小证据:page-protocol/page-runtime/shared host、api-client、Settings Auth Center、SignInPage 的定向测试;desktop 与 390px 验证单实例、多实例、注册开关和失败状态。
  • 安全 red-team:直接伪造 public_variables、篡改/跨认证器 authenticator_id、调用未知或不匹配的 public Auth route、禁用实例、secret-shaped config、重复注册、并发注册、客户端 role/owner 字段。
  • migration preview:先统计需要回填、已有非空 Block、缺失 provider default 和异常 config 的实例;任何非空覆盖计数必须为 0。
  • rollback:发布前保留旧公开发现 contract 的可回退数据库版本;一旦用户已编辑 public_ui_block,回滚必须先导出/保留该用户内容,不能通过降级丢弃。运行时不保留第二份 Core 表单作为“回滚”。
  • 进入验收使用 qa-evaluation,warning/coverage 与最终 QA 证据写入 tmp/test-governance/
  • 延后证据:workspace 级 full Cargo、full frontend build、coverage 和完整 repo verify 可交给 CI-beta;若定向证据无法覆盖 contract/migration 风险,则不得延后。

停止与重构条件

  • 必须新建 Auth 专用 TSX/AST/renderer/runtime,或必须降低 canonical 代码区块既有能力,才能继续。
  • Core 必须按 auth_type、注册开关或其他业务变量解释并生成认证 UI。
  • 公开登录页必须依赖 Frontstage page/document/block-code 资源,或必须维护第二份 UI 内容真值。
  • Provider 必须直接写 users、identities、sessions、roles/workspace memberships,绕过 Auth Center 才能完成注册。
  • 当前系统没有安全的注册 provisioning policy,且无法从后端配置明确默认归属、角色、激活/验证语义。
  • public projection 无法证明不泄漏 secret/raw options,或 public Auth route 无法重新校验当前认证器、provider 与持久化配置。
  • migration/reconcile 会覆盖任意非空用户 Block、改变历史身份绑定,或无法对缺失 provider default 的实例 fail closed。
  • [Root] Frontstage TSX 代码区块作者平台:OpenAPI 源码、区块联动与运行工作台 #1393 canonical Block/ctx.api contract 在实现前发生破坏性变化,导致本 Issue 需要拥有第二套协议;此时回到本 Issue 更新合同,不做前端兼容猜测。

生命周期

  • 当前阶段:phase:implementation
  • 实施授权:用户已于 2026-07-24 确认本 Single Issue 并明确要求开始实现;实现中若发现缺少安全 provisioning policy,按停止条件回到 discussion。/
  • 关闭条件:AC-001~AC-011 全部结算,migration preview/rollback 和集中 QA 证据齐备,合入 protected beta 后由用户完成最终验收。

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiPublic API or protocol contract workarea:backendBackend API, service, repository, or runtime workarea:frontendFrontend UI or interaction workarea:runtimeRuntime and execution behaviorarea:schema-uiSchema UI contracts, renderers, and form behaviorarea:settingsSettings console and configuration surfacescontractContract or API semantics changegrade:g4Architecture or data risk workmigrationDatabase or persisted data migrationneeds-backendNeeds backend workneeds-frontendNeeds frontend workneeds-qaNeeds QA or acceptance validationphase:user-acceptanceWaiting for user acceptanceplan:singleSingle executable issue with one acceptance boundarysecuritySecurity or sensitive data boundarytype:featureFeature or new capabilityuser-dataMay expose or affect user-owned content

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions