# App 账号安全接入

2026-10-03。复用项目内 Better Auth / Expo 1.7.7，新增“我的 → 账号安全”，按浅色、中英文设计实现。没有新增认证框架、账号 store 或验证码服务；账号注销尚未开放。

## 功能

| 页面 | 行为 |
| --- | --- |
| 账号安全 | 显示当前邮箱，进入更换邮箱和登录会话；未登录进入既有邮箱登录页 |
| 登录会话 | 读取官方当前用户会话；标明当前会话、客户端、IP、登录时间；其他会话先确认再撤销；客户端/IP仅供识别，不能作为设备认证 |
| 更换邮箱 | 先验证原邮箱，再验证新邮箱；保留同一 user.id，不重置注册时间、额度、追剧、观看记录或邀请关系 |
| 结果未确认 | 撤销后用 GET 确认目标消失；改邮箱后用 GET 确认同一账号/会话的新 verified email；桥接失败保留“确认结果”，不自动重复 POST |

原邮箱验证码使用官方 `email-verification`，新邮箱验证码由 `requestEmailChange` 生成并绑定原、新邮箱。200 只表示请求被接受；不承诺邮件已经送达，也不提前宣称邮箱已改。会话超过框架的近期验证期限时，提供既有邮箱复验入口。

会话撤销 token 只留在当前页面内存；不放入导航、查询键或持久化缓存。OTP 提交后清空。页面离开、origin/用户/会话变化会中止旧请求，迟到响应不能填入新的账号页。

## 本机处理

权威会话 null 或账号终态清除当前 origin 的官方 Expo 凭据；本机清理复用原 progress journal、viewer 与查询缓存。桥接暂时失败不能保留已确认失效的旧身份。网络不可用仍是未知结果，不冒充服务端撤销。

当前播放活动捕获起始账号和认证会话。确认退出、停用或更换账号/会话后，关闭旧 reporter、卸载原生 VideoStage、禁用旧媒体计划与下一集预取。这个已确认结果在本次播放活动内保持，不被后续 503 或迟到回调恢复；重新进入剧集才开始新的播放活动。普通首次网络错误不会被当成撤销。

已发出的第三方裸视频地址和完全离线内容无法靠删除登录会话即时收回。旧下载没有账号许可字段，本段不声称已把它变成受控离线库。

## 实现位置

- `src/auth/account.ts`：官方 SDK 薄适配，普通可导入函数，以 base、真实账号/会话及可选 AbortSignal 调用。
- `src/auth/client.ts`：复用 origin 分区与现有请求 generation，删除官方 SecureStore 键，权威会话核对。
- `src/screens/AccountScreen.tsx`：账号页、会话确认和双邮箱流程；My、导航与中英文资源接入。
- `src/auth/ConsumerAuthGate.tsx`、`src/consumer/queries.ts`：权威失效与旧业务身份清理。
- `src/playback/useConsumerProgress.ts`、`src/screens/PlayerScreen.tsx`：关闭已失效的当前播放活动。

## 验证

App 全套 166/166、TypeScript 检查通过：原有 148 项，加 8 项实际官方 SDK 检查、7 项实际账号页 React 检查、2 项身份/进度 hook 检查和 1 项实际播放器撤销检查。HTTP、SecureStore 和 native 组件采用本地替代，不是实体设备运行。

[独立复审](dramivio-app-account-review.md)新增 16 组测试，并独立重跑相关作者 11 组。复审发现“已确认账号变化 → 后续网络失败”可恢复旧播放的 P2；修复后保留原失败证据、相同预期复验通过。服务端能力与验证范围见[生命周期接入](dramivio-account-lifecycle-foundation.md)及[服务端独立复审](dramivio-account-lifecycle-review.md)。

实际 Better Auth / PostgreSQL 双邮箱验证另行证明 user.id、createdAt、既有片单、逐集位置与 E00 owner 保留。生产邮件投递、Android/iOS 真机、系统凭据故障、账号注销、离线许可和正式发布仍待验收。

## 页面复核

实际 AccountScreen 与官方 SDK 另通过 RN Web / Metro 本地浏览器预览：390×844 中英文会话列表、撤销确认与 GET 确认后的列表、原邮箱和新邮箱验证码步骤。输入框 52px、按钮 48px，无横向溢出；没有阴影或把撤销 token 放到画面。页头、身份、HTTP 和原生组件在这个预览使用本地替代，因此截图不是 Android/iOS 真机凭证。

![中文登录会话](app-account-preview/devices-390-zh.png)

![英文更换邮箱](app-account-preview/email-390-en.png)
