# 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 分钟后再试` | `{"what":"auth","retry_after_seconds":60}` | | 锁定期间再次登录 | **429** | 同上(N 随剩余时间递减) | 同上 | | 登录成功 | 200 | `ok` | 正常 auth 信息 | 实测样例(连错 2 次触发锁定,阈值为 2 的租户): ```json // 第 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 分钟内再试」**。客户端直接展示即可,无需自行拼接时间 | | `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. 客户端处理建议 1. **错误识别**:登录失败回调中判断 `code == 429`(或 SDK 异常携带的 ctrl code)。仅 `429` 按锁定处理,`401`/`403` 维持现有文案与逻辑。 2. **文案展示**: - 优先展示服务端 `text`(已含剩余分钟数,中文); - `text` 为空时的兜底文案:`登录错误次数过多,请稍后再试`。 3. **禁止静默重试**:锁定期间重试不会带来额外后果(不刷新锁定时间、不计新失败),但每次都得到 429 提示,建议拿到 429 后**禁用登录按钮或展示倒计时**(用 `retry_after_seconds`),引导用户等待或走找回密码。 4. **倒计时精度**:`retry_after_seconds` 为剩余秒数(比真实剩余时间多算 1 秒余量),客户端倒计时结束即可恢复登录,无需与服务端时钟同步。 5. **多端一致**: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 秒)加速验证。