6.2 KiB
6.2 KiB
IM 登录失败锁定 - 移动端对接文档
功能:用户登录密码连续输错达到配置阈值后,账号暂时锁定;锁定期间登录请求被服务端直接拒绝。本文档面向原生移动端(Android / iOS,基于 Tinode SDK)对接者。 版本:v1(2026-09-20) | 服务端版本:im_server(已发布至 dev)
1. 功能交互总览
移动端登录(basic 认证,协议不变)
├─ 密码正确 → 计数清零,登录成功(行为与现状完全一致)
├─ 密码错误(未达阈值)→ 401 authentication failed(现状不变)
├─ 密码错误达到阈值 → 429 账号锁定(message 含剩余时间)
└─ 锁定期间再次登录(无论密码对错)→ 429,服务端不校验密码直接拒绝
- 登录协议与请求结构零变更:锁定逻辑全部在服务端(im_server basic 认证链路),移动端只做错误展示适配。
- 阈值/时长由管理后台配置:【安全管理→安全策略】的登录限频策略,按租户下发(不同租户配置可能不同),客户端不可配置、无需缓存。
- 解锁途径:① 锁定时间自然到期自动解锁;② 用户联系客服/管理员,在管理后台【日志审计→登录失败日志】手动解锁。两种途径均无需客户端参与。
2. 错误响应契约(核心对接点)
2.1 响应结构(WebSocket 传输)
登录 {login} 消息的 ctrl 响应:
| 场景 | code | text | params |
|---|---|---|---|
| 密码错误,未达阈值 | 401 | authentication failed |
— |
| 密码错误达到阈值,触发锁定 | 429 | 登录错误次数过多,账号已锁定,请 N 后再试(N 按剩余时长显示:不足 1 分钟为「1 分钟以内」,不足 1 小时为「1 小时以内」,不足 1 天为「N 小时」,其他为「N 天」) |
{"what":"auth","retry_after_seconds":60} |
| 锁定期间再次登录 | 429 | 同上(N 随剩余时间递减) | 同上 |
| 登录成功 | 200 | ok |
正常 auth 信息 |
实测样例(连错 2 次触发锁定,阈值为 2 的租户):
// 第 1 次错误密码
{"ctrl": {"id": "t1", "code": 401, "text": "authentication failed", "ts": "..."}}
// 第 2 次错误密码(达到阈值)
{"ctrl": {"id": "t1", "code": 429,
"text": "登录错误次数过多,账号已锁定,请 1 分钟以内再试",
"params": {"what": "auth", "retry_after_seconds": 60},
"ts": "..."}}
// 锁定期间(约 12 秒后)正确密码登录,同样被拒绝且剩余时间递减
{"ctrl": {"id": "t1", "code": 429,
"text": "登录错误次数过多,账号已锁定,请 1 分钟以内再试",
"params": {"what": "auth", "retry_after_seconds": 48},
"ts": "..."}}
2.2 字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | HTTP 语义状态码。429 = 账号锁定,与 401(密码错误)区分 |
text |
string | 面向用户展示的完整中文文案,剩余时长自动格式化:不足 1 分钟显示「1 分钟以内」,不足 1 小时显示「1 小时以内」,不足 1 天按小时(向下取整),其他按天(向下取整)。客户端直接展示即可,无需自行拼接时间 |
params.retry_after_seconds |
int | 剩余锁定秒数(向上取整),可用于 UI 倒计时/禁用登录按钮 |
params.what |
string | 固定 auth,表示错误发生在认证环节 |
2.3 gRPC 传输(Android SDK 默认)
gRPC 通道下服务端返回相同的 ctrl 结构(code/text/params 逐字段保留),SDK 会将其封装为带 code 的登录异常抛出。识别方式不变:code == 429。
3. 客户端处理建议
- 错误识别:登录失败回调中判断
code == 429(或 SDK 异常携带的 ctrl code)。仅429按锁定处理,401/403维持现有文案与逻辑。 - 文案展示:
- 优先展示服务端
text(已含剩余分钟数,中文); text为空时的兜底文案:登录错误次数过多,请稍后再试。
- 优先展示服务端
- 禁止静默重试:锁定期间重试不会带来额外后果(不刷新锁定时间、不计新失败),但每次都得到 429 提示,建议拿到 429 后禁用登录按钮或展示倒计时(用
retry_after_seconds),引导用户等待或走找回密码。 - 倒计时精度:
retry_after_seconds为剩余秒数(比真实剩余时间多算 1 秒余量),客户端倒计时结束即可恢复登录,无需与服务端时钟同步。 - 多端一致:Web 端(im_webapp)已按本契约实现(
errors.ts的 429 分支),移动端保持相同交互语义。
4. 服务端行为细节(影响测试预期)
| 行为 | 说明 |
|---|---|
| 计数对象 | 按账号名(username,不区分大小写)哈希计数,与设备/IP 无关:换设备登录同一账号同样累计 |
| 计数窗口 | 滑动窗口 window_seconds(默认 30 分钟):窗口内累计达到阈值即锁定;窗口过期后重新计数 |
| 锁定时长 | lock_seconds(默认 15 分钟),从触发锁定的那次失败请求起算 |
| 锁定期内正确密码 | 仍返回 429(校验前置于密码比对),且不刷新锁定时间(剩余秒数持续递减) |
| 锁定期内请求 | 不写入失败审计日志(避免日志膨胀) |
| 成功登录 | 计数与锁定记录立即清零 |
| 仅 basic 认证 | 锁定只作用于 basic scheme(账号密码)登录;token 重连不受影响 |
| 策略关闭 | 租户未配置或 enabled=false 时,行为与旧版完全一致(无 429) |
5. 自测要点
| 用例 | 预期 |
|---|---|
| 错误密码 × (阈值-1) 次 | 每次 401,文案「账号或密码错误」 |
| 错误密码第 N 次(达阈值) | 429 + 锁定文案 + retry_after_seconds ≈ lock_seconds |
| 锁定期内用正确密码 | 仍 429,retry_after_seconds 递减 |
| 等待锁定到期(或联系管理员解锁) | 正确密码登录成功 200 |
| 登录成功后再连错 (阈值-1) 次 | 均 401(成功登录已清零历史计数) |
注:测试环境的阈值/时长以【安全管理→安全策略】当前发布版本为准,联调时可临时调小(如 2 次/60 秒)加速验证。