主题
XHIM 企业账号治理
本文面向购买方的 IM 管理员、身份平台开发者和私有化部署运维人员,说明账号的 停用、恢复与注销边界。账号治理属于服务端权威状态,不应由客户端本地字段或 管理页面缓存推断。
1. 状态模型
| 服务端状态 | 管理台显示 | 可否登录/续签 | 管理动作 |
|---|---|---|---|
active | 已启用 | 可以 | 停用、注销 |
suspended | 已停用 | 不可以 | 恢复、注销 |
unregistered | 已注销 | 不可以 | 不可恢复 |
- 停用立即撤销当前账号的有效设备会话。客户端收到稳定原因
account_suspended后必须清理登录态并回到登录页;管理员填写的内部原因 不会下发给客户端。 - 恢复只把账号状态改回
active,不会恢复任何旧 Token 或已撤销会话。 用户必须重新完成购买方身份认证并签发新会话。 - 注销是不可恢复的匿名化治理操作。客户端收到稳定原因
account_unregistered;管理台不会提供“恢复注销账号”。只有原mutation_id且请求内容完全相同的幂等重放可以返回原成功回执;任何新的 注销、恢复或其他生命周期 mutation 都返回403 account_unregistered, 不会伪装为changed=false成功。
1.1 客户端处理合同
普通 SDK 只读账号状态,不暴露 suspend/unsuspend/unregister 写 API。 客户端可从 accountStateChanged 强类型事件收到:
| 字段 | 合同 |
|---|---|
state | unknown / active / suspended / unregistered |
kickedReason | none / account_suspended / account_unregistered |
revision | 正整数为权威版本;0 为旧 frame 未提供 revision |
accountEpoch | 只处理与当前登录账号匹配的事件 |
connectionGeneration | 屏蔽旧连接迟到事件 |
Facade 会在退出/关闭边界失效旧 epoch,屏蔽重复或降序 revision, 并取消普通在途请求。应用收到 suspended/unregistered 后要终止 自动续凭、销毁账号容器并回到登录页。同一事实也可能先作为请求 错误出现:
- ABI status 105 / stable code
account_suspended; - ABI status 106 / stable code
account_unregistered。
两者 retryable=false,不进入 Token 刷新、重连风暴或普通网络错误 HUD。 事件和错误都只包含固定枚举原因,管理员输入的 reason 不下发、 不展示、不记录到客户端日志或分析事件。
旧 Core 不产生 kind 17,旧 Server 也不支持治理写入;新 Facade 在这个 组合下继续保留原普通 SESSION_REVOKED 兼容行为,不伪造强类型账号事件。
2. 注销不是物理级联删除
注销会匿名化可识别的公开账号资料和登录身份,并撤销当前会话,但它不是对 数据库做物理级联删除:
- 已有聊天记录、群事件和不可覆盖的安全审计记录继续按购买方的数据保留策略 保存;
- 服务端保留内部不透明关联键,避免破坏消息序列、群成员历史、合规审计和 取证完整性;
- 管理台对匿名化条目显示“已注销用户”,
display_name和public_user_id可以为空;内部user_id只在折叠的“审计标识”中用于 精确辨认,不作为普通展示名; - 需要执行监管意义上的删除、导出或保留冻结时,应另走购买方审批后的隐私与 数据生命周期流程,不能把“注销成功”当成物理擦除证明。
3. 管理后台
使用部署管理员账号登录同源 /admin/,打开“用户管理”。页面提供:
全部账号、已启用、已停用、已注销状态筛选与稳定游标分页;- 昵称和
public_user_id优先展示,内部user_id仅作为折叠审计辅助; - 每次变更携带页面刚读取的
revision,服务端以 CAS 拒绝覆盖并发修改; - 每个操作意图生成随机
mutation_id,同一次失败重试保持该 ID,避免重复 提交;关闭确认框后再次发起才生成新 ID; - 停用/恢复要求填写原因并确认;注销还要求风险勾选、输入目标确认短语和最终 二次确认;
- 变更成功后立即重新读取账号库存和安全审计。发生
revision_conflict时先刷新服务端权威状态,再由管理员重新决定; - 管理员会话使用
HttpOnly/同源 Cookie 和内存 CSRF。页面不会把管理员密钥、 密码或明文治理原因写入localStorage、sessionStorage或 URL。
4. Admin API 合同
4.1 库存
http
GET /v1/admin/users?app_id=APP_ID&after_user_id=CURSOR&limit=100
GET /v1/admin/users/disabled?app_id=APP_ID&after_user_id=CURSOR&limit=100现有用户库存的每一项增量返回:
json
{
"state": "active",
"revision": 7,
"lifecycle_changed_at_ms": 1786230000000
}停用/注销专用库存响应为:
json
{
"items": [
{
"app_id": "com.customer.im",
"user_id": "opaque-internal-user-key",
"public_user_id": "XH10002341",
"display_name": "林晨曦",
"state": "suspended",
"revision": 8,
"lifecycle_changed_at_ms": 1786230000000,
"reason_summary": "离职流程已审批"
}
],
"next_after_user_id": "opaque-internal-user-key",
"has_more": true
}reason_summary 只用于受控管理库存;不会进入 SDK 用户资料、实时事件或客户端 错误正文。
4.2 变更
http
POST /v1/admin/users:suspend
POST /v1/admin/users:unsuspend
POST /v1/admin/users:unregisterjson
{
"app_id": "com.customer.im",
"user_id": "opaque-internal-user-key",
"mutation_id": "admin-user-suspend-UUID",
"expected_revision": 7,
"reason": "离职流程单 OA-2026-0088"
}注销请求必须额外传入 "confirm": true。成功响应是服务端权威回执:
expected_revision 必须是正整数;reason trim 后必须为 1–256 个 UTF-8 字节。调用方必须按 UTF-8 字节数校验,不能把 256 个中文字符误当成 256 字节。
json
{
"app_id": "com.customer.im",
"user_id": "opaque-internal-user-key",
"state": "suspended",
"revision": 8,
"changed_at_ms": 1786230000000,
"changed": true,
"idempotent_replay": false,
"revoked_session_count": 3
}畸形 JSON 返回 400 invalid_request;字段合法性(包括注销未明确确认)返回 400 invalid_argument。其他稳定错误包括 401 unauthorized、403 forbidden、 403 account_unregistered、 404 not_found、409 revision_conflict 和 409 idempotency_conflict。 客户端不得在冲突后递增本地版本重试,必须重新读取目标账号。
5. 业务后台 Server API
购买方的 OA、HR、IAM 或 SSO 后台可调用:
http
POST /v1/server/users:suspend
POST /v1/server/users:unsuspend
POST /v1/server/users:unregister
POST /v1/server/users/disabled:list它们使用与其他 /v1/server/* 路由相同的独立 Server-to-Server 凭证:请求头 X-XHIM-Business-Key。不能新增另一套 X-Server-Key,也不能从浏览器或 客户端 App 调用。字段、CAS、幂等、注销确认和响应语义与 Admin API 一致; 业务后台应把 HR/OA 工单号放入 reason。原因 trim 后必须为 1–256 个 UTF-8 字节(中文按实际 UTF-8 字节计算),不要放密码、Token 或私钥。
6. 旧版本兼容
旧 XHIM Server 不提供账号治理:
- 基础
GET /v1/admin/users仍可读取,旧响应没有state/revision;管理台会 禁用治理按钮,不把缺字段伪装成active; - 停用/注销库存和变更路由返回 404 时,应显示“请升级服务端”,不能回退到
users:upsert、会话撤销或本地标记来伪造成功; - 新管理台配旧 Server 只能做旧版基础管理;新 Server 配旧管理台不会自动执行 任何账号生命周期变更。
7. 迁移、部署与回滚
- 先备份 PostgreSQL,并在隔离恢复库验证备份可用;记录当前镜像摘要、Schema 版本和管理台版本。
- 使用目标发行包自带的迁移程序执行前向迁移。不要手工创建账号状态、revision、 幂等或审计表,也不要让多个实例并发执行迁移。
- 迁移成功后滚动升级 XHIM Server;确认
/health/ready、管理员登录、基础用户 列表、四种状态筛选和一组测试账号的停用→重新登录失败→恢复→重新签发 Token 链路。 - 注销验收必须使用专门测试账号,并核对公开资料匿名化、会话撤销、消息/审计 仍可按策略读取;不得使用生产真实账号做破坏性演练。
- 应用回滚只有在发行兼容矩阵允许时才切回旧二进制。已执行的前向数据库迁移 默认保留,不运行破坏性逆迁移;旧 Server 不理解治理能力时应暂停治理写入, 不能宣称回滚后仍可操作。
- 回滚不会恢复被停用/注销前的 Token,也不会逆转已经提交的注销匿名化。 数据恢复属于单独审批的灾难恢复流程,不是普通应用回滚。
本仓库完成的是代码和文档,不代表任何客户环境已经部署。真实发布必须另行留存 制品摘要、迁移日志、健康检查、Admin API 验收与回滚证据。