账号体系业务逻辑说明

这一页是给产品经理新人看的「账号体系说明书」。它不讲代码,只讲三件事: 用户会经历哪些流程每种异常该怎么拦拦下来之后该怎么告诉用户。 页面里所有数值(60 秒、5 次、15 分钟、30 分钟…)都直接读取自 assets/js/config.js,所以文档和实现永远一致。

怎么用这一页:先去 注册页 走一遍正常流程, 再故意输错验证码、故意连错 5 次密码,然后回到这一页对照 ⑤ 和 ⑥ 两张表, 你会立刻明白"为什么产品经理必须写异常流"。

① 业务目标与角色说明

业务目标

让用户顺利进来

注册流程的唯一 KPI 是注册转化率:每一步校验都必须在"拦住无效提交"和"别让用户烦"之间取舍。

让用户稳定回来

登录流程的核心是成功率与安全性的平衡:既要让正常用户一次登进来,也要挡住撞库与暴力破解。

别让用户丢掉账号

找回密码是留存兜底。它做不好,用户不是"改天再来",而是直接换产品。

关键角色

账号体系涉及的角色、诉求与典型场景
角色 核心诉求 典型场景 对产品的启发
新用户 尽快用上产品,不愿意填太多信息 用手机号注册,只想收一个验证码 字段越少越好;注册成功直接登录,别让用户再输一次
老用户 快速登录,长期免登录 回访时勾选「记住我」 提供 7 天免登录;登录态到期要有明确提示而不是静默失效
忘记密码的用户 找回账号,且过程必须可信 换手机后想不起来旧密码 验证身份 → 设置新密码分成两步,中途失败可重来,每一步都告知当前进度
恶意用户 / 脚本 批量注册、撞库、刷短信 用脚本高频请求验证码 必须有发送频率限制、每日上限、失败锁定、验证码等机制
客服 / 运营 能解释用户遇到的情况 用户反馈"我登不上,一直提示锁定" 错误码体系要规范,客服能凭错误码快速定位原因

② 注册 / 登录 / 找回密码完整流程图

下面三张图用纯 HTML + CSS 绘制(没有引入任何图表库)。 深蓝圆角 = 开始/结束,浅蓝方块 = 处理步骤,黄色菱形 = 判断条件, 绿色 = 通过分支,红色 = 拦截分支。

注册流程

登录流程

找回密码流程

③ 状态机:账号在生命周期里会处于哪些状态

画状态机的好处是:你能一眼看出"还有哪些状态没考虑提示"。 每多一个状态,就多一组"进入条件 + 退出条件 + 界面表现 + 提示文案"要定义。

未注册 账号不存在于用户表
已注册 存在账号,但未登录
已登录 持有有效登录态
锁定 连续失败 5 次,禁止登录
重置中 已通过验证,持有重置凭证
已重置 密码已更新,需重新登录
本机实时状态 计算中…

正在读取本机数据…

这块面板直接读取你浏览器里的 localStorage(键名前缀 ),每秒刷新一次。 试着在另一个标签页注册、登录或故意输错密码,回到这里就能看到状态跟着变。

状态迁移表:从哪个状态、因为什么事件、迁移到哪个状态、界面要如何表现
起始状态 触发事件 目标状态 界面表现与提示
未注册 完成注册(验证码 + 密码 + 协议全部通过) 已登录 提示「注册成功,已为你自动登录」并跳转个人中心
已注册 密码正确 + 未处于锁定 已登录 提示「登录成功」,写入登录态,跳转个人中心或 redirect 页面
已注册 密码错误,失败次数 < 5 已注册 inline 标红密码框,提示「密码错误,还可以尝试 N 次」
已注册 密码错误,失败次数 = 5 锁定 顶部红色横幅 + 15 分钟倒计时,提交按钮禁用
锁定 锁定时间到期 已注册 横幅转为「锁定已解除,现在可以重新登录了」,按钮恢复可用
已登录 点击退出登录(二次确认) 已注册 提示「已安全退出登录」并回到首页;其他标签页下次检查时同步退出
已登录 登录态到期 / 本地数据被清除 已注册 提示「登录状态已过期」并跳转登录页,携带 redirect 便于登录后返回
已注册 找回密码验证通过 重置中 生成 30 分钟凭证,跳转设置新密码页并显示剩余有效时间
重置中 凭证过期 / 链接无效 / 直接访问无 token 已注册 整页错误态说明原因,3 秒后自动跳回找回密码页,避免死页面
重置中 提交合规的新密码(与旧密码不同) 已重置 提示「密码已重置,请使用新密码登录」,作废凭证并清除登录态
已重置 使用新密码登录成功 已登录 正常进入个人中心,流程闭环完成

④ 字段与校验规则表

写 PRD 时,字段表是最容易被漏掉的部分。判断一条规则有没有写清楚,标准是: 开发看完能不能不问你就写出正则和提示文案。 下面表格里的数值全部来自 config.js,改配置即改文档。

账号字段校验规则
字段 必填 校验规则 触发时机 失败提示
账号(注册 / 登录 / 找回) 支持手机号或邮箱:
手机号正则 (11 位,1 开头,第二位 3-9)
邮箱规则:
input 纠错 / blur 完整校验 / submit 全量校验 请输入正确的手机号或邮箱,手机号需为 11 位,邮箱需包含 @ 与域名
验证码(注册 / 找回) 纯数字;Demo 固定为
有效期 ,发送间隔
blur 校验格式 / submit 全量校验 + 接口校验内容 验证码为空、位数不对、内容错误、已过期分别给不同提示
密码(注册 / 重置) 长度
至少包含大写字母、小写字母、数字、特殊字符中的
input 实时刷新强度条 / blur 校验 / submit 全量校验 长度不符提示当前位数;类别不足提示"当前仅 N 类"
确认密码 必须与密码字段完全一致 input / blur 即时比对 / submit 全量校验 两次输入的密码不一致,请重新确认
新密码(重置) 在密码规则基础上,额外要求与旧密码不同 submit 时由接口层比对旧密码 新密码不能与旧密码相同,请更换一个密码
协议勾选 必须勾选《用户协议》与《隐私政策》 submit 时校验;勾选后立即清除警告 请先阅读并勾选同意《用户协议》与《隐私政策》
记住我(登录) 勾选:登录态
不勾选:仅当前会话有效
submit 时读取 无需提示;个人中心会显示当前生效方式
重置凭证 token 是(URL 参数) 必须存在、与本地记录一致、未过期;有效期 ;一次性使用 进入重置页时立即校验 + 提交时再次校验 缺失提示"链接不完整";无效提示"链接无效或已使用";过期提示"链接已过期"

密码强度分级规则

强度条的分档逻辑(与 validation.js 实现一致)
强度 判定条件 进度条颜色 是否允许提交
未输入 密码框为空 灰色(0 格)
长度不足 或字符类别少于 红色(1 格) 否,需要继续输入
长度达标且满足 类字符 黄色(2 格)
满足 4 类字符且长度 ≥ 12 位 绿色(3 格) 是(推荐等级)
产品经理提醒:强度条是"引导"而不是"门槛"。 如果强行要求必须达到"强"才允许提交,用户会大量流失; 正确做法是"允许中等强度提交,但用可视化鼓励用户加强"。

⑤ 异常分支与拦截策略表

这张表是账号体系 PRD 的核心。每一行都回答三个问题: 什么情况下会出问题系统怎么拦拦完怎么让用户有路可走。 最后一列"可恢复性"尤其重要 —— 好的拦截一定给用户留出口。

全部异常分支与拦截策略(对应代码里的错误码)
流程 异常场景 错误码 拦截策略 提示方式 用户可恢复路径
通用 账号为空 ACCOUNT_REQUIRED 提交前拦下,不发请求 inline 标红 + toast 补填即可
账号格式错误(既不是手机号也不是邮箱) ACCOUNT_FORMAT 正则不通过即拦下,blur 时提前提醒 inline 标红并说明正确格式 修正格式后重试
网络异常 / 接口失败 NETWORK_ERROR 统一降级提示,不改变页面状态;按钮恢复可点击 红色 toast「网络开小差了,请检查网络后重试」 重试即可;可用首页开关复现
注册 账号已存在 ACCOUNT_EXISTS 发送验证码前、提交注册前各拦一次 inline + toast「该账号已注册,请直接登录」 提供「去登录」入口
验证码为空 / 格式不对 CODE_REQUIRED / CODE_FORMAT 提交前格式校验 inline 提示需 6 位数字 补填或修正
验证码错误 CODE_INVALID 接口比对失败,不消耗验证码次数 inline + toast 提示错误 可重新输入;也可重新获取
验证码已过期 CODE_EXPIRED 超过 即判定失效 黄色警告 toast,提示重新获取 点击「获取验证码」重新发送
发送过于频繁 CODE_TOO_FREQUENT 距上次发送不足 ,按钮保持禁用 提示还需等待的秒数 倒计时结束后自动可点
未勾选协议 / 密码不合规 AGREEMENT_REQUIRED / PASSWORD_LENGTH / PASSWORD_STRENGTH / PASSWORD_MISMATCH 提交前全量校验,定位到具体字段 inline 标红 + toast 汇总数量 按提示逐项修正
登录 账号不存在 ACCOUNT_NOT_FOUND 查表失败即拦下,不进入密码比对 inline + toast「该账号未注册,请先注册」 提供「去注册」入口
密码错误(未达锁定阈值) PASSWORD_WRONG 失败计数 +1,返回剩余尝试次数 inline 标红 + 提示「还可以尝试 N 次」 重新输入;忘记密码可走找回
连续失败达到 ACCOUNT_LOCKED 写入锁定截止时间, 内拒绝一切登录尝试 顶部红色横幅 + 实时倒计时,按钮禁用 倒计时结束自动解锁;也可通过重置密码间接解锁
已登录用户再次访问登录页 检测到有效登录态直接放行 轻提示后自动跳转个人中心 无需操作
登录态过期 SESSION_EXPIRED / NO_SESSION 访问受保护页面时校验,失效即跳登录页 警告 toast + 带 redirect 跳转 重新登录后自动回到原页面
找回 / 重置 账号未注册 ACCOUNT_NOT_FOUND 发送验证码前拦下 inline + toast「该账号未注册,请先注册」 提供「去注册」入口
凭证缺失 / 无效 TOKEN_MISSING / TOKEN_INVALID 进入重置页立即校验,不渲染表单 整页错误态 + toast,3 秒后自动跳回找回页 重新验证身份获取新凭证
凭证过期 TOKEN_EXPIRED 超过 即失效并清除本地记录 黄色警告态 + 倒计时归零时立即切换 重新走找回密码流程
新密码与旧密码相同 PASSWORD_SAME_AS_OLD 接口层比对旧密码后拦下 inline 标红 + toast 提示更换 换一个密码即可
可恢复性检查法:把每个异常都问一遍"用户看到这条提示之后,下一步能做什么?" 如果答案是"不知道"或"找客服",那这个拦截设计就是失败的。

⑥ 提示文案规范表

文案是用户唯一能"看见"的校验逻辑。写文案最大的坑是只描述现象、不给原因、不给动作。 下面每一行都遵循「发生了什么 + 为什么 + 现在该怎么办」的三段式。

三条文案铁律: ① 不甩技术术语(不要出现 "401"、"token invalid"); ② 不用责怪语气(不要出现 "你输入错了"); ③ 一定给出下一步动作(重试 / 重新获取 / 去登录 / 去注册)。
按场景整理的文案模板与实际使用文案
场景 文案模板(三段式) 本项目实际文案 反例(不要这样写)
账号为空 [缺什么] + [为什么重要] + [怎么填] 请输入手机号或邮箱 参数错误 / error
账号格式错误 [格式要求] + [示例] 请输入正确的手机号或邮箱,手机号需为 11 位,邮箱需包含 @ 与域名 格式不正确
账号已注册 [结论] + [替代动作] 该账号已注册,请直接登录 手机号重复
账号未注册 [结论] + [替代动作] 该账号未注册,请先注册 用户不存在
验证码发送成功 [动作完成] + [有效期] + [仍可发送次数] 验证码已发送:123456(60 秒内有效),今日还可发送 9 次 发送成功
验证码错误 [结论] + [动作] 验证码错误,请检查后重新输入 验证码错误
验证码过期 [原因] + [动作] 验证码已过期,请重新获取(有效期 60 秒) 失效
发送过于频繁 [原因] + [具体还要等多久] 发送过于频繁,请 43 秒后再试 请求过于频繁
当日达上限 [结论] + [恢复时间] 今日验证码发送次数已达上限(10 次),请明天再试 超出限制
密码长度不符 [要求] + [当前情况] 密码长度需为 8-32 位,当前 5 位 密码太短
密码强度不足 [要求] + [当前情况] 密码需至少包含大小写字母、数字、特殊字符中的 3 类,当前仅 2 类 密码太简单
两次密码不一致 [结论] + [动作] 两次输入的密码不一致,请重新确认 密码不匹配
新密码与旧密码相同 [原因] + [动作] 新密码不能与旧密码相同,请更换一个密码 非法密码
未勾选协议 [动作] + [原因] 请先阅读并勾选同意《用户协议》与《隐私政策》 请勾选协议
密码错误(未锁定) [结论] + [剩余机会] + [替代方案] 密码错误,还可以尝试 3 次(忘记密码可走找回流程) 密码错误
账号锁定 [状态] + [原因] + [解锁时间倒计时] 账号已被锁定,请于 14 分 32 秒后再试 登录受限
重置链接过期 [状态] + [有效期] + [动作] 重置链接已过期(有效期 30 分钟),请重新获取 链接失效
网络异常 [通俗原因] + [动作] 网络开小差了,请检查网络后重试 Network Error
系统兜底 [通用原因] + [动作] 系统繁忙,请稍后重试 未知错误 500

⑦ 成功 / 失败 / 警告 / 信息:四类提示怎么用

本 Demo 的提示分了四种颜色,不是"为了好看",而是对应四种不同的用户处境。 分不清该用哪个,就会出现"红色警告刷满屏但用户根本不知道自己错在哪"的经典问题。

成功 success(绿色)

含义:操作已完成,且结果是用户想要的。

使用场景:

  • 注册成功并自动登录
  • 登录成功
  • 退出登录完成
  • 密码重置成功
  • 演示数据一键重置完成

失败 error(红色)

含义:操作未完成,且原因需要用户修改输入或稍后重试。

使用场景:

  • 账号格式错误
  • 验证码错误
  • 两次密码不一致
  • 密码错误
  • 账号已存在 / 不存在
  • 网络异常与系统兜底

警告 warning(黄色)

含义:当前操作被限制或即将失效,需要用户注意,但还没"失败"。

使用场景:

  • 发送验证码过于频繁(被动等待)
  • 验证码 / 重置链接已过期
  • 账号被锁定,倒计时中
  • 登录态已过期需重新登录
  • 未勾选协议(提醒但不算错误)

信息 info(蓝色)

含义:纯告知,不需要用户做任何纠错动作。

使用场景:

  • 提示 Demo 固定验证码是 123456
  • 告知重置凭证还有多久失效(正常状态下的提示)
  • 模拟网络异常开关已关闭
  • 页面说明类提示
提示类型的判断决策表(从用户视角判断,而不是从工程师视角)
问自己 答"是"时用什么
操作成功完成了吗? 成功(绿)
用户能通过修改输入自己解决吗? 失败(红),并把错误标在具体字段下方
用户什么都做不了,只能等或重新发起流程? 警告(黄),并给出剩余等待时间
只是告知信息,不影响任务继续? 信息(蓝)
同一个错误既有 inline 提示又有 toast,会不会太吵? 字段错误用 inline,跨字段/流程级错误用 toast,二者不重复播报同一条

⑧ 埋点建议:怎么用数据判断账号体系好不好

账号流程是典型的"漏斗"。没有埋点,你只能知道"注册量下降了",但不知道为什么。 下面是本 Demo 实际埋的事件名(可直接在代码里搜索到),以及每个事件能回答什么问题。

埋点事件清单(事件名与 config.js 中 EVENTS 常量同源)
事件名 触发时机 建议携带参数 能回答的问题
page_view 每次页面加载 page 各流程页面的流量分布与来源占比
register_start 用户点击注册提交(或首次输入账号) 账号类型(手机号/邮箱)、来源页 有多少人真的开始尝试注册
register_send_code 点击获取验证码 账号(脱敏)、当日第几次 验证码环节的流失率与异常发送占比
register_success 注册成功且已写入登录态 账号(脱敏)、账号类型 注册转化率 = 成功 / 开始
register_fail 注册被拦截 错误码 哪一类错误最常把用户挡在门外
login_start 点击登录 是否勾选记住我 登录发起量、免登录偏好
login_success 登录成功 账号(脱敏)、记住我 登录成功率、日活回访质量
login_fail 登录失败(密码错误或账号不存在) 错误码、已失败次数 是否存在撞库攻击、是否存在账号枚举探测
login_locked 账号被锁定 失败次数 锁定策略是否过严(高频触发说明阈值需要调整)
logout 主动退出登录 登录时长 会话时长分布,用于评估"记住我"天数是否合理
forgot_start 进入找回密码并校验账号 账号(脱敏) 忘记密码的发生频率
forgot_send_code 找回流程中发送验证码 账号(脱敏) 找回流程的验证码环节流失
reset_token_created 身份验证通过并生成重置凭证 账号(脱敏) 从"发起找回"到"验证通过"的转化率
reset_password_success 密码重置成功 账号(脱敏) 找回密码整体闭环率(核心指标)
reset_password_fail 重置被拦截 错误码 凭证过期率是否偏高(说明 30 分钟太短)

看数据的方法:三个漏斗 + 两条安全线

注册漏斗

page_view(注册页)→ register_start → register_send_code → register_success。 哪一段掉得最多,问题就在哪一段。

登录漏斗

login_start → login_success。如果 login_fail 集中在少数账号上,基本可以判定是撞库。

找回漏斗

forgot_start → reset_token_created → reset_password_success。 凭证过期率高就说明有效期设置不合理。

两条安全线:reset_token_created 的绝对量突然暴涨,往往意味着有人在批量尝试重置他人账号; ② login_fail 的错误码若大量是 ACCOUNT_NOT_FOUND, 说明有人在用手机号段扫描已注册账号,需要加验证码或风控。

本机实际产生的埋点流水(可实时观察)

下面这块显示的是你在本 Demo 里的真实行为记录,来自 localStorage 的 events。 注意:payload 里只放脱敏账号,绝不记录明文密码

⑨ 安全与合规说明(写进 PRD 的硬要求)

先把话说清楚:本 Demo 为了让你"看得见数据",把用户密码以明文存在 浏览器 localStorage 里,并且所有校验都在前端完成。 这在真实生产中是严重违规的。下面列出的每一条,都是上线前必须补齐的。

Demo 现状 vs 生产要求对照

上线前必须补齐的安全与合规项
维度 本 Demo 的做法(仅供演示) 真实生产必须怎么做 不做的后果
校验位置 前端校验为主,mock-api.js 再校验一次做示意 后端必须独立做全量校验,前端校验只作为体验优化 绕过页面直接调接口即可写入脏数据、越权注册
传输安全 无网络请求,纯本地 全站 HTTPS,禁止 HTTP 回退,开启 HSTS 密码可被中间人明文窃听
密码存储 localStorage 明文存储 服务端加盐哈希(bcrypt / scrypt / Argon2),永不可逆、永不落明文日志 一库泄露全站账号沦陷
限流与风控 仅本地模拟 60 秒间隔、每日 10 次、失败 5 次锁定 服务端按 IP / 设备 / 账号多维限流,接入风控与行为验证码,异常直接拦截 被刷短信(直接烧钱)、被撞库拖垮数据库
验证码 固定 123456,直接显示在页面上 服务端随机生成、加盐哈希后存储、限次校验、一次性作废;短信只下发不落库 固定验证码等于没有验证码
重置凭证 本地生成随机 token,30 分钟有效,一次性 服务端生成高熵随机串,绑定账号与用途,一次有效,使用后全量失效同账号其他凭证 凭证可预测则账号可被任意接管
会话管理 localStorage + sessionStorage 标记模拟 HttpOnly + Secure + SameSite Cookie 存会话票据;敏感操作二次验证 XSS 可直接窃取登录态
账号枚举 分开提示"账号不存在"和"密码错误"(便于教学) 统一提示"账号或密码错误";找回密码对未注册账号也返回相同响应 攻击者可批量探测出哪些手机号已注册
审计日志 本地埋点流水,仅用于教学演示 服务端记录登录、改密、重置、锁定等敏感操作日志,保留时长符合法规,可追溯 出事无法定位,合规审查不通过
隐私合规 协议勾选 + 提示"数据仅存本地" 明示收集目的与范围、最小必要原则、单独同意、提供注销与数据导出通道 违反《个人信息保护法》,面临处罚与下架
敏感信息脱敏 埋点与展示统一使用脱敏账号(如 138****8888) 日志、埋点、客服后台全部脱敏;禁止在埋点 payload 中出现密码类字段 数据泄露面被放大,内部人员可批量获取账号
前端构建 零依赖纯静态,无第三方脚本 配置 CSP、依赖锁定与漏洞扫描,避免引入被投毒的第三方资源 供应链攻击可导致全站被劫持

一句话总结给产品经理

前端校验管体验,后端校验管安全

两边规则必须完全一致。前端做"即时反馈",后端做"最后一道门"。 在 PRD 里写校验规则时,务必写明"前后端一致,以后端为准"。

所有限制都要有"出口"

限流、锁定、过期这些机制一定会误伤正常用户。 所以必须配套:倒计时可见、过期可重新获取、锁定可自动解除、被封可找客服。

⑩ 测试用例:正常流程 · 异常流程 · 边界值

验收时最容易被漏掉的是"边界值"。经验法则是: 对每一个数值规则,都至少测 最小值 - 1、最小值、最大值、最大值 + 1 四个点。

A. 正常流程(Happy Path)

主流程必须一次通过,用于回归验证
编号 前置条件 操作步骤 预期结果
N-01 无本地数据 注册页输入手机号 → 获取验证码 → 填 123456 → 设置合规密码 → 勾选协议 → 提交 提示注册成功,自动登录并跳转个人中心,显示该账号
N-02 已有账号 A 登录页输入 A + 正确密码 → 勾选记住我 → 登录 登录成功跳转个人中心;登录方式显示"账号密码登录",到期时间为 7 天后
N-03 已登录 个人中心点击退出登录 → 二次确认 提示已安全退出,回到首页;再访问个人中心自动跳登录页
N-04 已有账号 A 找回密码:输入 A → 获取验证码 → 填 123456 → 提交 生成本地重置凭证,跳转重置页并显示脱敏账号与倒计时
N-05 持有有效凭证 输入合规新密码(与旧密码不同)→ 确认 → 提交 提示密码已重置,跳转登录页并显示绿色引导横幅
N-06 密码刚被重置 用新密码登录 登录成功,闭环完成;用旧密码登录应失败
N-07 未登录 直接访问 dashboard.html 跳转 login.html?redirect=dashboard.html,登录后自动回到个人中心

B. 异常流程(Error Path)

每个异常都必须有明确提示,不允许静默失败
编号 操作步骤 预期结果
E-01 注册时账号留空直接提交 账号字段标红并提示"请输入手机号或邮箱",同时 toast 汇总,不发生跳转
E-02 输入 12345 作为手机号提交 提示格式错误,说明需为 11 位手机号或合法邮箱
E-03 输入 abc@@qq 作为邮箱提交 提示邮箱格式不正确
E-04 用已注册账号走注册流程并获取验证码 提示"该账号已注册,请直接登录",不发送验证码
E-05 验证码输入 000000 提示验证码错误,验证码未被消耗,可重新输入
E-06 发送验证码后等待 60 秒以上再提交 提示验证码已过期,需重新获取
E-07 60 秒内重复点击「获取验证码」 按钮处于禁用状态并显示剩余秒数,无法重复发送
E-08 同一账号当日发送验证码第 11 次 提示"今日验证码发送次数已达上限(10 次),请明天再试"
E-09 密码输入 Ab1!(4 位)提交 提示长度需 8-32 位,并显示当前位数
E-10 密码输入 abcdefgh(仅小写,1 类)提交 提示需至少 3 类字符,并显示当前类别数
E-11 密码与确认密码不一致 确认密码字段标红,提示两次输入不一致
E-12 不勾选协议提交 提示需先阅读并勾选用户协议与隐私政策;勾选后警告自动消失
E-13 登录不存在的账号 提示"该账号未注册,请先注册"
E-14 连续输错密码 1~4 次 每次提示"密码错误,还可以尝试 N 次",N 正确递减
E-15 连续输错密码第 5 次 提示账号已锁定 15 分钟,顶部出现红色横幅并开始倒计时,提交按钮禁用
E-16 锁定状态下刷新页面 横幅与倒计时依然存在且时间准确(不是从头开始)
E-17 锁定状态下即使输入正确密码 仍然被拒绝,提示仍在锁定中
E-18 已登录时访问 login.html 自动跳转个人中心,不展示登录表单
E-19 找回密码输入未注册账号并获取验证码 提示"该账号未注册,请先注册",不发送验证码
E-20 直接访问 reset-password.html(不带 token) 显示错误态提示链接不完整,约 3 秒后自动跳回找回密码页
E-21 访问 reset-password.html?token=伪造的 提示重置链接无效或已使用,自动跳回找回密码页
E-22 重置时新密码与旧密码相同 提示"新密码不能与旧密码相同,请更换一个密码"
E-23 重置成功后再次使用同一个 token 链接 提示链接无效(凭证已被作废),需重新走找回流程
E-24 在首页打开"模拟网络异常"开关后提交表单 约 10% 概率出现红色 toast「网络开小差了」,按钮恢复可点击,页面不白屏
E-25 手动把 localStorage 中某个键改成非法 JSON 后刷新 页面正常渲染,坏数据被自动清理并回退默认值,控制台无报错
E-26 尝试构造 login.html?redirect=https://evil.com redirect 被白名单校验拒绝,登录后跳转个人中心而非外部站点

C. 边界值(Boundary)

对所有数值型规则,至少覆盖这四个点
编号 规则 边界输入 预期结果
B-01 密码长度 8-32 位 7 位 / 8 位 / 32 位 / 33 位 7 位与 33 位被拒绝;8 位与 32 位通过(仍需满足类别要求)
B-02 密码至少 3 类字符 2 类 / 3 类 / 4 类 2 类被拒绝;3 类判定为"中";4 类且长度 ≥ 12 判定为"强"
B-03 验证码 6 位数字 5 位 / 6 位 / 7 位 / 含字母 仅 6 位纯数字通过,其余提示格式错误(输入框限制 6 位)
B-04 手机号 11 位 10 位 / 11 位 / 12 位 仅 11 位且第二位为 3-9 通过
B-05 登录失败锁定 第 4 次 / 第 5 次 / 第 6 次 第 4 次仍可尝试;第 5 次触发锁定;第 6 次直接被锁定拦截
B-06 锁定 15 分钟 14:59 / 15:00 14:59 仍被拦截并显示倒计时;15:00 自动解锁,按钮恢复可用
B-07 验证码 60 秒有效期 59 秒 / 60 秒 / 61 秒 59 秒有效;60 秒起判定过期,提示重新获取
B-08 发送间隔 60 秒 59 秒 / 60 秒 59 秒时按钮仍禁用并显示"1 秒后重发";60 秒后可点击
B-09 每日发送上限 10 次 第 10 次 / 第 11 次 第 10 次成功并提示"今日还可发送 0 次";第 11 次被拒绝
B-10 重置凭证 30 分钟 29:59 / 30:00 29:59 可重置;30:00 起提示过期并跳回找回页
B-11 记住我有效期 勾选 / 不勾选 勾选为 7 天;不勾选关闭浏览器后失效(刷新页面仍有效)
B-12 超长输入 200 字符的邮箱 被格式校验拒绝或长度限制截断,页面不卡顿、不报错
测试小技巧:验证码有效期、发送间隔、锁定 15 分钟这些"等待类"规则, 调试时不必真的等。打开 config.js 把对应常量临时改小(例如 60000 改成 6000), 测完再改回来即可。

⑪ 产品设计要点总结

这七条是可以直接搬到任何表单类需求里的通用原则。每一条都标注了本 Demo 的具体落地位置, 方便你对照着看代码或页面表现。

① 防重复提交

问题:用户手抖点两下,就产生两条注册记录或两次扣费。

落地:提交时按钮立即进入 loading 并 disabled,同时设置 aria-busy="true";接口返回后统一恢复。见 ui.jssetButtonLoadingrunTask

② 实时校验,但别唠叨

问题:边打字边报错,用户还没输完就看到一片红,体验极差。

落地:blur(失焦)时完整校验并提示;input(输入中)只在"已经标红且现在已合规"时 立刻清除错误。既有反馈,又不打扰。见 auth-pages.jsbindRealtime

③ 错误要能定位

问题:只弹一句"请检查输入",用户不知道看哪儿。

落地:错误文案贴在该字段下方并标红边框;提交时自动滚动并聚焦第一个出错字段; 同时用 toast 汇总"还有 N 项需要修改"。

④ 容错:别把用户的努力清零

问题:一个字段错了就清空整个表单,用户会直接关掉页面。

落地:校验失败不清空任何已填内容;验证码错误不消耗发送次数; 锁定过期自动恢复且不要求刷新页面。

⑤ 等待必须可见

问题:按钮变灰却没说明原因,用户以为坏了。

落地:验证码按钮显示"43 秒后重发",锁定横幅显示"14 分 32 秒", 提交按钮显示 spinner 与"处理中…"。所有倒计时基于绝对时间戳,刷新页面依然准确。

⑥ 限制要有自动解除机制

问题:锁定后没人解锁,用户永远回不来。

落地:15 分钟自动解锁并切换为"锁定已解除"提示;验证码过期后可重新获取; 重置链接过期后自动跳回上一步而不是卡在死页面。

⑦ 全流程可恢复:每个异常都要有下一步

问题:用户碰壁后不知道去哪,只能找客服或直接放弃。

落地:每一条失败提示背后都配了一个出口 —— "该账号已注册,请直接登录"配「去登录」;"该账号未注册,请先注册"配「去注册」; "链接已过期"配"自动回到找回密码页";锁定提示配"倒计时结束后自动恢复"。 验收时可以逐条自查:这条提示下面,用户能点的是什么?

PRD 自查清单(写账号需求时逐条打钩)

检查项 是否写清楚 本 Demo 对应位置
每个字段的校验规则与失败文案 必写 本页 ④ 字段与校验规则表
每个异常的错误码与拦截时机 必写 本页 ⑤ 异常分支与拦截策略表
每个状态的进入/退出条件与界面表现 必写 本页 ③ 状态机
倒计时、有效期、锁定时间的具体数值 必写(不能写"一段时间") config.js RULES 常量
提示类型(成功/失败/警告/信息)的选择依据 建议写 本页 ⑦ 四类提示的使用场景
埋点事件名与参数 建议写 本页 ⑧ 埋点建议
安全与合规要求(哈希、HTTPS、限流、审计) 必写 本页 ⑨ 安全与合规说明
异常流与边界值测试用例 必写 本页 ⑩ 测试用例

⑫ 常见问题 FAQ

这七个问题是产品经理新人问得最多的。每一条都对应上面某个章节,可以互相对照阅读。

倒计时同时服务三个目的:给用户明确的等待预期(避免反复点击导致重复请求); 控制成本(短信按条计费,没有任何限制会迅速烧钱); 最基础的风控(配合每日 10 次上限,显著抬高刷验证码的成本)。

数值怎么定?通常取"正常用户收到短信所需时间 + 一点余量"。 60 秒是行业长期验证过的平衡点,太短会误伤,太长则让用户焦躁。

还有问题? 回到 演示首页 把流程再走一遍, 或者直接打开 注册页 故意制造几种错误, 对照本页 ⑤ ⑥ 两张表看看提示是否如你所料。