登录与身份安全 — 迭代需求
对应需求:REQ-ITER-008、REQ-ITER-009。本文覆盖尼日利亚手机号格式适配、跨设备登录验证和 App 单点登录。
已拍板:登录需要先做 OTP;仅在客户切换设备时才可能追加活体,且是否追加取决于客户是否已有可比对的 BVN 照片源。App 采用单点登录,同一账号同时只允许一个有效 App 会话。
1. 需求背景
本项目以手机号作为客户身份锚。手机号一旦格式混乱,同一个客户会被识别成多个客户;设备变更一旦不验证,账号被盗会直接影响借款和还款。
因此登录安全的底线是:
- 手机号必须规范化后入库和比较。
- 登录必须完成 OTP 验证。
- 首次登录、同设备登录、无历史可信设备的登录不要求活体。
- 仅在客户切换设备时判断是否需要追加活体;未完成 BVN 认证、没有 BVN 照片源的客户,切换设备也不要求活体。
- 已有活体认证且已有 BVN 照片源的客户,切换设备时必须追加活体验证,并与既有 BVN 查询照片比对。
- App 必须单点登录,避免同一账号多设备同时在线。
- 登录安全不能阻断正常客户换机。
2. 交互设计图
交互图参考当前登录页和验证码输入页:登录页先完成手机号格式输入和按钮可用性判断,验证码页只处理 OTP;仅切换设备时,OTP 通过后再按客户 BVN 认证状态决定是否进入独立活体验证页。
3. 手机号格式适配
3.1 规范化目标
统一保存为 E.164 格式:
+234XXXXXXXXXX展示时可按产品需要显示本地格式,但所有系统间传输、去重、登录、KYC 关联都使用规范化号码。
3.2 输入兼容
| 用户输入 | 规范化结果 |
|---|---|
08012345678 | +2348012345678 |
8012345678 | +2348012345678 |
2348012345678 | +2348012345678 |
+2348012345678 | +2348012345678 |
3.3 校验规则
- 只支持尼日利亚手机号。
- 去掉空格、横线、括号等格式字符。
- 默认国家码为
+234。 - 本地号码以
0开头时,去掉首位0后拼+234。 - 规范化后不满足长度或号段规则的,前端提示“请输入有效手机号”。
3.4 登录页交互细节
当前登录页保持左侧固定国家码 +234,用户只在右侧输入尼日利亚本地手机号主体。
| 状态 | 交互口径 |
|---|---|
| 初始状态 | 输入框展示 11 位占位内容 000 0000 0000,Register/Log in 按钮不可点击 |
| 输入首字符后 | 占位内容立即清除,只展示用户已输入数字 |
| 输入中 | 只允许输入数字;前端可按 XXX XXXX XXXX 分组展示,但提交前去掉空格 |
| 输入未满 10 位 | Register/Log in 按钮不可点击 |
输入满 10 位但首位为 0 | Register/Log in 按钮不可点击,并提示“请输入有效手机号” |
输入满 10 位且首位不是 0 | Register/Log in 按钮可点击,点击后发送 OTP |
登录页的前端强约束是 +234 后输入 10 位本地号码,且首位不能为 0。后台规范化能力仍需兼容 08012345678、8012345678、2348012345678、+2348012345678 等历史或接口输入格式。
3.5 Google 审核账号手机号
Google Play 审核需要可稳定登录的测试账号,但测试账号不能污染真实客户链路。V1.1 按“受控白名单手机号”处理:
| 项 | 口径 |
|---|---|
| 账号来源 | 由运营/产品配置 Google 审核手机号白名单 |
| 手机号格式 | 仍走同一套 E.164 规范化逻辑 |
| OTP | 可使用固定验证码或后台预置验证码,不调用真实短信供应商 |
| 活体 | 仅切换设备需要活体时,可返回模拟通过结果,不调用真实活体供应商 |
| 数据隔离 | 审核账号只能看到预置 demo 数据,不读取真实客户数据 |
| 单点登录 | 仍遵守 App 单点登录,避免多个审核设备同时污染会话 |
审核账号必须配置在服务端,不允许前端硬编码。生产环境只允许命中白名单的审核手机号走该逻辑,其他手机号一律走真实 OTP;只有切换设备时才按客户 BVN 认证和照片源状态决定是否追加活体。
4. 跨设备登录验证
4.1 设备定义
设备指 App 原生可稳定生成的设备标识组合,不使用单一可变字段作为唯一依据。
| 信号 | 用途 |
|---|---|
device_id | App 生成的安装级 ID |
device_fingerprint | 设备型号、系统、应用实例等摘要 |
last_login_device | 上次成功登录设备 |
sim_country / locale | 风险辅助 |
4.2 页面拆分
跨设备登录的 OTP 和活体必须拆成两个页面,不能放在同一页面:
| 页面 | 目的 | 展示条件 |
|---|---|---|
| OTP 验证页 | 验证手机号当前可触达 | 跨设备登录、同设备重新登录、审核账号登录等需要 OTP 的场景 |
| 活体验证页 | 验证当前操作者与既有 BVN 照片源一致 | 切换设备场景下 OTP 通过后,且客户已有活体认证和可用 BVN 照片源 |
OTP 验证通过后,后端返回下一步动作:login_success / need_liveness / blocked。前端只在切换设备且收到 need_liveness 时进入活体验证页。
OTP 验证页交互沿用当前验证码输入页:
| 状态 | 交互口径 |
|---|---|
| 进入页面 | 展示已发送验证码的手机号,验证码输入区为空,Register/Log in 按钮不可点击 |
| 输入验证码 | 4 个验证码位逐位填充,自动聚焦到下一位 |
| 未满 4 位 | Register/Log in 按钮不可点击 |
| 满 4 位 | Register/Log in 按钮可点击,点击后校验 OTP |
| 删除验证码 | 清除当前位并回退焦点;不足 4 位时按钮恢复不可点击 |
| 语音验证码 | 未收到短信时可点击 Try to via voice call 触发语音验证码,需遵守重试间隔和频控 |
4.3 触发条件
| 条件 | 动作 |
|---|---|
| 首次登录或无历史可信设备 | OTP,通过后登录成功,不要求活体 |
| 同设备正常登录 | 走原登录流程,不要求活体 |
| 切换设备,且未完成 BVN 认证 | OTP + 风险记录,不要求活体 |
| 切换设备,且已有活体认证和 BVN 照片源 | OTP + 独立活体验证 + 风险记录 |
| 设备变化且命中黑名单/冻结 | 阻断 |
| Google 审核手机号命中白名单 | 固定 OTP + 审核数据隔离;切换设备需要活体时可模拟通过 |
4.4 验证方式
V1.1 登录采用“OTP 必选、仅切换设备时活体有条件追加”的方式:
- OTP 用于证明手机号当前可触达。
- 活体用于证明当前操作者与既有 BVN 查询照片一致。
- 未进行 BVN 认证的客户,没有稳定照片比对源,切换设备也不要求活体。
- 已有活体认证且已有 BVN 照片源的客户,切换设备时需要活体验证。
- 活体比对数据源为客户历史 BVN 查询结果中的照片,不使用新设备本地照片或前端缓存作为基准。
- PIN 不作为 V1.1 跨设备登录必需条件。
- 活体失败时不允许在新设备登录。
- Google 审核账号仅在白名单命中时允许固定 OTP;切换设备需要活体时允许模拟通过。该豁免只为应用审核,不代表真实客户风控口径。
4.5 App 单点登录
同一客户在 App 端同时只允许一个有效会话:
| 场景 | 处理 |
|---|---|
| 同设备刷新登录态 | 保持当前会话 |
| 未 BVN 认证客户切换设备并完成 OTP 登录 | 新设备登录成功,旧设备会话失效 |
| 已有活体认证客户切换设备并完成 OTP + 活体登录 | 新设备登录成功,旧设备会话失效 |
| 旧设备继续请求接口 | 返回会话失效,提示重新登录 |
| 新设备活体失败 | 新设备登录失败,旧设备会话保持 |
单点登录范围覆盖 RocketCash 和 PocketBuy 客户端;PocketBuy SA 的 SA 工作台账号可单独按员工账号策略处理。
5. 数据要求
| 字段 | 说明 |
|---|---|
phone_normalized | E.164 手机号 |
phone_country_code | 国家码 |
device_id | 安装级设备 ID |
device_fingerprint_hash | 设备摘要 |
last_login_at | 最近登录时间 |
last_login_result | 成功 / 失败 / 阻断 |
risk_action | pass / otp_liveness / block |
session_id | 当前有效 App 会话 |
session_status | active / kicked / expired |
liveness_result | passed / failed / skipped |
bvn_verified_flag | 是否已完成 BVN 认证 |
bvn_photo_ref | 既有 BVN 查询照片引用 |
next_login_action | login_success / need_liveness / blocked |
account_type | real_customer / review_account |
review_account_flag | 是否 Google 审核账号 |
6. 验收标准
- 四类常见尼日利亚手机号输入能归一为同一格式。
- 同一客户不会因
080...和+23480...形成两个身份。 - 登录页手机号输入框初始展示 11 位
000 0000 0000占位内容。 - 登录页手机号输入首字符后,占位内容立即清除。
- 登录页
+234后输入未满 10 位时,Register/Log in按钮不可点击。 - 登录页
+234后输入满 10 位但首位为0时,Register/Log in按钮不可点击。 - 登录页
+234后输入满 10 位且首位不是0时,Register/Log in按钮可点击。 - 验证码页验证码未满 4 位时,
Register/Log in按钮不可点击;满 4 位后可点击。 - 新设备登录先进入 OTP 验证页,不在同一页面展示活体采集。
- 首次登录、同设备登录、无历史可信设备的登录不触发活体。
- 未完成 BVN 认证的客户切换设备时,OTP 通过后可登录,不触发活体。
- 已有活体认证且已有 BVN 照片源的客户切换设备时,OTP 通过后进入独立活体验证页。
- 活体验证使用既有 BVN 查询照片作为比对数据源。
- 按要求完成 OTP 或 OTP + 活体后更新可信设备。
- 新设备登录成功后,旧设备 App 会话失效。
- 旧设备会话失效后不能继续调用需登录接口。
- 活体失败时新设备不能登录,旧设备会话不受影响。
- 被冻结或黑名单客户在新设备登录时被阻断。
- 登录日志能追踪手机号、设备、验证动作和结果。
- Google 审核白名单手机号可使用固定 OTP 登录;切换设备需要活体时可通过模拟活体。
- Google 审核账号登录后只能看到 demo 数据,不能触发真实授信、放款、扣款和催收。
- 非白名单手机号不能使用审核账号逻辑。