视觉按最新原型,业务按已确认PRD。现有代码为满足设计而改造。执行见按设计实施与任务卡;当前代码与验证范围见消费者功能页。
A03 账号生命周期:服务端基础交接
本段接好成熟框架会话撤销与现有业务许可,并阻止已停用账号继续写入个人记录。未开放账号注销、未新增终态存储、未修改额度或邀请领域,也未发布到生产。
实现
| 文件 | 本段变化 |
|---|---|
services/platform/src/auth.mjs |
Better Auth 1.7.7 官方 session.delete.before 导入回调;官方批量撤销 before 回调;会话创建、续期及身份读写检查已有 owner;保留官方 OTP、Cookie、会话接口 |
services/platform/src/runtime.mjs |
查询既有安装批准,再调用已有 revokeInstallationSession 事务;批量操作按官方会话 owner 查询身份与批准的交集;普通查询释放连接后才启动业务事务 |
services/platform/src/state.mjs |
复用 entitlement_owner;H00/F00 写事务按原有表锁 → owner → 官方身份 session FOR SHARE → consumer_state_owner;等锁后判断终态及真实会话有效性;个人状态读取也检查 owner |
services/platform/src/platform.mjs |
已停用个人 API 返回 403;内部身份桥返回 user:null;四个个人写操作显式传入官方 session.id,客户端 body 不能替换身份 |
services/platform/tests/lifecycle.test.mjs |
真实隔离 PostgreSQL、官方 HTTP、单连接数据库、超过 100 个会话、故障与终态竞态回归 |
services/platform/tests/state.test.mjs、platform.test.mjs |
显式执行所需 E00 migration;没有捕获缺表错误并假装账号活跃 |
初始化顺序明确为 Auth → Catalog → E00 → State → Referrals → Search。独立调用 State 的项目也必须完成 E00 migration;缺表会真实失败。刚完成邮箱验证、尚无业务 owner 行的用户可以正常开始第一项业务操作,写入时创建并锁住既有 owner。
已确认行为
- 无安装批准的普通 Web 会话可以正常退出。
- 退出、撤销指定会话、撤销其他会话、撤销全部会话,会撤销已有安装批准并释放其 pending 播放预留;旧 Cookie 不能继续提交进度。
- 停用账号不能创建新官方会话,不能读取或续期旧会话,不能通过身份桥重新登录业务层,不能将游客额度并入旧账号。
- 一个 report 即使已经通过鉴权,只要等 owner 行锁时发生停用,事务仍返回 account_terminal;sequence、位置、观看区间不会写入。
- 账号仍活跃但本设备会话已撤销或过期时,等锁中的 report、begin、following/update、history/delete 也会返回 login_required 并回滚。身份 ID 来自官方 get-session,不能用请求 body 中的新会话 ID 替换。
- 写事务持有真实身份行的 FOR SHARE 锁,官方身份 DELETE 必须等该事务完成;因此不会在身份已删除后再提交旧写入。这里校验数据库既有行,没有新增会话存储或协议。
- 正常账号仍使用官方续期。读取 active 快照后才发生停用的迟到续期,也由 session.update.before 阻止;get-session.after 还会拒绝迟到的身份结果。
- 不修改用户原注册时间,也不重置额度、邀请关系或旧业务归属。
复审关闭的框架边界
Better Auth 默认 findMany 最多 100 行,而批量删除可以删除全部身份行。已使用官方 advanced.database.defaultFindManyLimit = Number.MAX_SAFE_INTEGER,没有换成另一个任意业务上限。该选项影响框架未显式设置 limit 的 findMany;本产品开放的会话操作按当前用户查询全部会话元数据。
框架还会吞掉批量删除前快照的读取异常。官方批量路由 before 现在先以官方 get-session 的 disableRefresh/disableCookieCache 读取当前身份,再查询既有批准与身份行的交集并撤销。此步骤失败即停止身份批量删除。单条 session.delete.before 仍保留;已撤销批准直接跳过,避免重复业务事务。
官方 sign-out 本身会吞掉数据库删除错误、清除客户端 Cookie,并返回 200。保留该框架行为;200 不能证明服务端会话已撤销。实际故障测试确认原 Cookie 仍可能有效,客户端必须使用既有的一次旧 Cookie 对账,并将无法确认的结果展示为未确认。单条与批量 revoke 的失败不能当作已完成。
根代理追加了一个具体竞态调查:已鉴权的 HTTP report 等 owner 锁期间,官方 Web 会话被真正删除,旧实现仍返回 200,并写入 sequence=1、position=18。已在同一业务事务内用官方会话行关闭这一 P2;没有以入口复查代替事务检查。普通直接导入的 State 调用可以不提供 authSessionId,因为它是受信服务组合,不能把这种调用方式当作公共认证入口。
验证
- A03 定向:22/22,真实 PostgreSQL 18 RAM 容器与随机 loopback 端口,7.664 秒。
- 单连接 pool 的官方退出、指定/其他/全部撤销真实执行成功,没有嵌套占用连接。
- 105 个其他会话 + 当前会话:官方列表返回 106,撤销其他后仅剩当前;再次建立 105 个会话后撤销全部,身份行、未撤批准、pending 预留均为 0。
- 实际 SDK 批量快照 SELECT 单次失败:域批准仍已先撤销,预留释放。
- 域撤销事务失败:官方批量请求失败,身份行保留,批准及预留未被伪报为成功;恢复数据库后可使用原会话重试。
- 单条退出、指定会话撤销的快照 SELECT 失败:框架没有删除身份行,原 Cookie / 官方列表仍可确认会话存在,批准及 pending 也保留;显式重试后真正撤销。这个行为与批量删除不同,没有为它添加重复的单条 before 回调。
- 新增撤销竞态检查覆盖四种 HTTP 写操作、已鉴权后过期、缺失及错 owner 会话、客户端替换会话 ID 无效。真实 pg_stat_activity 确认 Auth DELETE 会等待写事务的会话行共享锁;受信直接域调用仍兼容。
- 作者全平台累计测试 133/133,13.743 秒,19 个顶层组,包含根代理的真实官方双邮箱验证测试
email-change.test.mjs。此前批量与单条故障的独立证据见 第一段独立复审报告。追加会话撤销竞态由根代理另写隔离脚本完成对照复现与当前版本 7 组独立验证,见在途写入追加复验。本段与第一段子 agent 证据分别记录。
范围
批准记录及来源能力由隔离测试的可信夹具创建。正式 App 证明发行者与真实受控媒体许可尚未接入,不宣称这里已经发放 App 50 集许可、撤销外部供应商已签发的视频令牌,或实现完整离线库。
读取全量会话及逐条撤销批准有对应元数据与事务成本;本段验证了 106 个会话,没有完成大规模压力测试。身份删除与业务批准撤销沿用两个成熟事务,失败可先收紧部分许可,不能宣称跨框架原子提交;并发新证明发行必须在后续真实发行者接入时验证。
账号注销按钮、永久删除、双邮箱页面、下载许可与前端本机清理不属于本段;由后续独立实施与验收接入。本段不启用 Better Auth deleteUser。