20 KiB
20 KiB
F1 统一认证与账户中心
涉及端:用户端(
Case-Database-Frontend-user)+ 后端(Case-Database-Backend)关联文档:
- API 契约:api-contracts.md §2.1 用户端认证
- 数据模型:data-model.md §4.1 用户与权限域
- UI 规范:ui-specs-user.md
- 参考原型:
docs/reference/登录页.html
目标与边界
- 在保持本系统独立账号体系前提下,实现与企业数字化平台便捷互通登录
- 覆盖账号登录、短信登录、扫码登录、OAuth 登录、企业 SSO、注册、找回密码与个人中心
- 完善验证码、风控、审计、会话安全与协议合规,不在前端和日志中存储敏感明文
开发状态说明
- 🟢 已完成 — 前后端均已联调可用
- 🟡 前端已完成 — 前端 UI 和交互已实现,待后端对接
- 🟠 前端部分完成 — 前端 UI 存在但逻辑为占位/模拟,需补全
- ⚪ 待开发 — 前后端均未开发
功能清单
| 编号 | 功能 | 优先级 | 状态 |
|---|---|---|---|
| F1.1 | 多模式登录(账号 / 短信 / 扫码) | P0 | 🟠 部分完成 |
| F1.2 | 第三方授权登录(微信 / QQ) | P1 | 🟠 仅入口 UI |
| F1.3 | 账户辅助功能(自动登录 / 忘记密码) | P0 | 🟠 部分完成 |
| F1.4 | 全局主题切换(深色 / 浅色) | P1 | 🟢 已完成 |
| F1.5 | 简易个人中心 | P1 | 🟠 仅基础展示 |
| F1.6 | 用户注册 | P0 | 🟠 仅 UI 框架 |
| F1.7 | 安全管理后台 | P1 | ⚪ 待开发 |
| F1.8 | 企业 SSO 集成 | P1 | ⚪ 待开发 |
| F1.9 | 多端会话管理 | P2 | ⚪ 待开发 |
F1.1 多模式登录(P0) — 🟠 部分完成
开发现状
| 子功能 | 前端 | 后端 | 说明 |
|---|---|---|---|
| 左右分屏布局 | ✅ | — | LoginView.vue + LoginBanner.vue |
| 账号密码登录 | ✅ | ✅ | LoginTabPanel.vue → useLoginForms.handleLogin → authApi.login 已联调 |
| 短信登录表单 | ✅ | ❌ | UI 已实现(Headless UI TabPanel),但逻辑仅 Toast 提示"短信登录未实现" |
| 密码明文切换 | ✅ | — | AppInput.vue 已支持 |
| 账号/短信标签页切换 | ✅ | — | Headless UI TabGroup 实现 |
| 扫码登录 | ❌ | ❌ | 未实现(无二维码图标入口、无二维码区域) |
| 图形验证码 | ✅ | ✅ | 拼图滑块验证码已实现,登录/注册/发短信前触发 |
| 登录成功跳转 redirect | ✅ | — | 路由守卫已携带 redirect 参数,登录后跳转已实现 |
| Loading 态 | ✅ | — | 提交时按钮 Loading 态已实现 |
| 错误提示统一 | ❌ | ❌ | 当前直接暴露后端原始错误,未做统一化处理 |
用户故事
作为用户,我希望通过账号、短信和扫码三种方式快速登录,并在异常场景下得到明确、可恢复的提示。
功能描述
- 登录页采用左右分屏:左侧品牌展示,右侧认证功能区
- 账号登录与短信登录通过表单内顶部标签页切换(仅两个标签:账号登录 / 短信登录)
- 账号登录:
username或手机号 + 密码,支持明文切换 - 短信登录:手机号 + 短信验证码
- 扫码登录:点击输入区右上角二维码图标切换到二维码区域(独立于标签页)
交互细节
- 账号/短信切换:两个标签页原地切换,共享底部区域(第三方登录入口、协议勾选)
- 扫码切换:点击二维码图标后,整个表单区(含标签页)执行
fade + slide过渡替换为二维码区;二维码区右上角提供"返回账号登录"图标,点击后恢复表单 - 二维码区包含:二维码、刷新按钮、剩余有效时间(180 秒)和状态文本
- 扫码状态流转:等待扫描 → 待用户确认 → 确认中 → 登录成功
- 二维码过期自动刷新并提示"二维码已更新,请重新扫码"
- "登录"与"发送短信"前,均需通过图形验证码挑战
表单与校验规则
username:4-20 位,字母数字下划线phone:符合中国大陆手机号格式password:8-20 位,必须同时包含字母和数字,拒绝常见弱口令(后端维护弱口令黑名单,如12345678、password、qwerty123)sms_code:6 位数字,5 分钟有效- 密码强度指示(注册和修改密码场景显示):弱 = 仅满足最低长度和字符要求;中 = 含大小写混合或特殊字符;强 = 12 位以上且含大小写 + 数字 + 特殊字符
- 登录错误提示统一为"账号或密码错误"或"账号或校验信息不匹配"
错误与加载态
- 提交按钮进入 Loading 态,防重复点击
- 网络超时:提示"网络异常,请稍后重试"
- 验证码过期:提示并自动刷新验证码挑战
- 风控限流:返回剩余重试时间,并提示稍后再试
- 账号锁定:提示锁定时长和解锁路径(短信解锁或等待)
登录成功跳转
- 如果用户登录前访问了需认证的页面(被拦截跳转到登录页),登录成功后自动跳回该页面
- 前端通过 URL query 参数
redirect携带原始路径,登录成功后读取并跳转 redirect值必须为站内相对路径,禁止跳转到外部 URL(防开放重定向攻击)- 无
redirect参数时默认跳转首页
验收标准
- 账号密码登录可认证并跳转首页
- 账号/短信标签页可正常切换,共享底部区域
- 登录成功后跳回
redirect指定的站内页面 - 密码输入支持明文/密文切换
- 提交按钮有 Loading 态
- 短信登录对接后端 API(当前为占位)
- 扫码登录功能完整实现
- 登录/发送短信均经过图形验证码验证
- 二维码支持倒计时与自动刷新
- 错误提示统一化处理(不暴露后端原始错误)
F1.2 第三方授权登录(P1) — 🟠 仅入口 UI
开发现状
| 子功能 | 前端 | 后端 | 说明 |
|---|---|---|---|
| 微信/QQ 登录入口展示 | ✅ | — | ThirdPartyLogin.vue 已渲染图标 |
| OAuth 跳转 | ❌ | ❌ | 按钮无点击事件 |
| 回调处理 | ❌ | ❌ | 无回调页面和逻辑 |
| 手机号绑定引导 | ❌ | ❌ |
用户故事
作为用户,我希望使用微信或 QQ 一键登录,避免重复注册。
功能描述
- 登录区底部展示微信、QQ 登录入口
- 首次授权自动创建账号并建立绑定,后续直接登录
交互细节
- OAuth 流程:跳转授权页 → 授权 → 回调 → 绑定或登录 → 跳转原页面
- 未绑定用户引导补充手机号(若第三方未提供可靠手机号)
- 已绑定用户直接签发本系统会话 Token
数据约定
- 首次 OAuth 创建账号时,
users.source设为对应 provider(wechat/qq) - 手机号冲突处理:若 OAuth 返回的手机号已被其他本地账号绑定,提示用户"该手机号已注册,请用该手机号登录后在个人中心绑定",不自动合并
验收标准
- 微信/QQ 登录入口 UI 已展示
- 微信 OAuth 跳转和回调流程完整可用
- QQ OAuth 跳转和回调流程完整可用
- 已绑定用户直接登录,未绑定用户进入绑定流程
F1.3 账户辅助功能(P0) — 🟠 部分完成
开发现状
| 子功能 | 前端 | 后端 | 说明 |
|---|---|---|---|
| 自动登录勾选 UI | ✅ | ❌ | LoginTabPanel.vue 勾选框已实现,但未真正影响会话有效期 |
| 忘记密码表单 UI | ✅ | ❌ | ForgotPanel.vue 表单已实现,含用户名/手机号/验证码/新密码字段 |
| 忘记密码提交逻辑 | ❌ | ❌ | useLoginForms.handleForgot 为 setTimeout 模拟,无 API 调用 |
| 验证码发送 | ❌ | ❌ | sendCode 仅 Toast 提示,无真实发送 |
用户故事
作为用户,我希望系统记住登录状态并在忘记密码时快速恢复访问。
功能描述
- 自动登录:勾选后延长会话有效期(30 天)
- 忘记密码:账号/手机号 + 短信验证码 + 新密码重置
找回密码流程
- 输入账号或手机号(至少填一项;OAuth 用户可能无 username,此时仅填手机号即可)
- 验证关联手机号并发送短信验证码
- 校验验证码后设置新密码并确认
- 重置成功后跳转登录页
安全规则
- 错误提示统一为"账号或校验信息不匹配",避免账号枚举
- 新密码不可与最近一次密码相同
- 重置成功后主动使历史会话失效
验收标准
- 自动登录勾选 UI 可用
- 忘记密码表单 UI 完整(含用户名、手机号、验证码、新密码字段)
- 自动登录勾选后真正延长会话有效期
- 忘记密码对接后端 API
- 短信验证码发送对接后端 API
- 重置密码后旧会话失效
F1.4 全局主题切换(P1) — 🟢 已完成
开发现状
| 子功能 | 前端 | 后端 | 说明 |
|---|---|---|---|
| 主题切换图标 | ✅ | — | 登录页已实现切换按钮 |
| 深色/浅色双主题 | ✅ | — | 使用 @vueuse/core 的 useDark + useToggle |
| 偏好持久化 | ✅ | — | useDark 自动持久化到 localStorage |
| 系统偏好跟随 | ✅ | — | useDark 默认跟随 prefers-color-scheme |
用户故事
作为用户,我希望在深色模式和浅色模式间切换,以适配不同使用环境。
功能描述
- 顶部导航栏提供主题切换图标
- 支持浅色/深色两套主题,并在本地持久化
- 支持
prefers-color-scheme初次自动跟随
验收标准
- 切换后全局 UI 立即生效
- 刷新页面后主题偏好保持
- 核心页面在深色模式下可读性正常(需全页面回归验证)
F1.5 简易个人中心(P1) — 🟠 仅基础展示
开发现状
| 子功能 | 前端 | 后端 | 说明 |
|---|---|---|---|
| 导航栏用户信息展示 | ✅ | ✅ | AppNavbar.vue 展示昵称或"用户",已登录/未登录切换正常 |
| 下拉菜单 | ❌ | — | 无下拉菜单组件,无个人信息/修改密码/绑定管理入口 |
| 退出登录 | ❌ | ❌ | 导航栏无退出入口,userStore.logout 方法已存在但未绑定到 UI |
| 账号注销 | ❌ | ❌ |
用户故事
作为已登录用户,我希望查看自身信息并管理账户安全相关操作。
功能描述
- 顶部导航右侧展示头像、昵称、角色标签
- 下拉菜单:个人信息、修改密码、绑定管理、退出登录
- 支持账号注销入口(7 天冷静期,可撤销)
验收标准
- 登录态展示用户昵称,未登录态展示"登录"链接
- 导航栏增加下拉菜单(个人信息、修改密码、绑定管理、退出登录)
- 退出登录功能可用
- 账号注销流程含冷静期提示与撤销能力
F1.6 用户注册(P0) — 🟠 仅 UI 框架
开发现状
| 子功能 | 前端 | 后端 | 说明 |
|---|---|---|---|
| 注册表单 UI | ✅ | — | RegisterPanel.vue 已实现(用户名、手机号、验证码、密码、确认密码) |
| 昵称字段 | ❌ | — | 当前注册表单缺少昵称输入项 |
| 密码强度指示 | ❌ | — | 未实现 |
| 协议勾选 | ❌ | — | 未实现 |
| 注册提交逻辑 | ❌ | ❌ | useLoginForms.handleRegister 为 setTimeout 模拟,无 API 调用 |
| 验证码发送 | ❌ | ❌ | 仅 Toast,无真实发送 |
auth.ts 注册 API |
❌ | ❌ | 未定义 register 方法 |
用户故事
作为新用户,我希望通过账号注册快速完成开户并进入系统。
功能描述
- 注册字段:账号(username)、昵称(nickname)、手机号、短信验证码、密码、确认密码
- 昵称为选填,留空时系统自动生成默认昵称(如"用户_" + 随机 6 位字符)
- 页面实时显示密码强度(弱/中/强)
- 注册前必须确认协议(默认未勾选)
校验规则
- 账号唯一,手机号唯一
- 账号不允许使用系统保留词(
admin、system、root、test、api、null、undefined等),后端维护保留词列表 - 账号须通过敏感词过滤,拒绝包含违规内容的用户名
- 昵称长度限制 2-30 字符,同样需通过敏感词过滤
- 密码复杂度:8-20 位,必须同时包含字母和数字,拒绝常见弱口令(如
12345678、password、qwerty123),后端维护弱口令黑名单 - 短信验证码 5 分钟有效,错误次数达到阈值后触发风控
数据约定
- 注册创建账号时,
users.source设为local users.user_type注册时固定为user,管理员仅由后台创建
验收标准
- 注册表单基础 UI 已实现(用户名、手机号、验证码、密码、确认密码)
- 注册表单补充昵称字段
- 密码强度实时指示
- 协议勾选组件及拦截逻辑
- 注册对接后端 API(
authApi.register) - 短信验证码对接后端 API
- 系统保留词和敏感词被拒绝并给出明确提示
- 协议未同意时不可提交注册
F1.7 安全管理后台(P1) — ⚪ 待开发
功能描述
- 黑名单管理:IP、设备指纹、账号维度封禁/解封
- 登录日志:时间、IP、设备、登录类型、成功/失败、风控命中原因
- 账号锁定记录:支持检索与手动解锁
- 风控策略配置:阈值、封禁时长、白名单
验收标准
- 可查看和检索登录审计日志
- 可配置限流和锁定策略
- 支持手动解封和白名单管理
F1.8 企业 SSO 集成(P1) — ⚪ 待开发
用户故事
作为企业内部用户,我希望从企业数字化平台无感知进入本系统。
设计原则
- 本系统保持独立账号池和会话体系
- 企业平台作为外部 IdP,通过桥接流程完成认证
- 协议优先级:OIDC/OAuth2(首选)> 自定义签名票据(兜底)
账号映射策略
- 优先按
enterprise_user_id绑定本地账号 - 未绑定时按手机号/邮箱进行二次确认绑定
- 仍无匹配账号则创建外部来源账号并标记来源
直达登录要求
- 支持企业平台深链:
state+nonce+ 回调白名单 - 凭据短时效、一次性使用,防重放
- SSO 登录失败可回退本地登录
验收标准
- 企业用户可从外部平台直达登录
- 首次登录自动完成绑定或创建
- 企业平台不可用时,本地登录路径不受影响
F1.9 多端会话管理(P2) — ⚪ 待开发
功能描述
- 个人中心展示当前账号在线会话列表(设备、地区、最近活跃时间)
- 支持手动踢出指定会话
- 系统可配置是否允许多端同时在线(单点挤占)
验收标准
- 可查看在线会话并识别当前设备
- 支持踢出其他设备并即时生效
- 单点挤占模式下,新登录会使旧会话失效
图形验证码与协议合规 — ⚪ 待开发
图形验证码规范
- 挑战类型:拼图滑块(slider puzzle)
- 触发点:登录提交、发送短信、注册提交、找回密码关键步骤
- 交互流程:
- 前端调用
POST /api/auth/captcha/challenge,后端生成随机target_x位置(60 ~ width-60),连同captcha_token、width、target_x一起返回 - 前端展示拼图区域:上方为带有缺口(target gap)的背景图案,缺口位于
target_x处;滑块控制一个拼图块在背景上水平移动 - 用户拖动滑块将拼图块对齐缺口位置,松手后前端提交
answer_x到POST /api/auth/captcha/verify - 后端校验
abs(answer_x - target_x) <= tolerance(tolerance = 10px),通过后标记captcha_verified:{token} - 验证通过后前端获得一次性
captcha_token(5 分钟有效),提交业务请求时携带,后端校验后立即销毁
- 前端调用
- 视觉反馈:拼图块接近缺口时(误差 ≤ 10px),缺口和拼图块同步变为绿色,提示用户已对齐
- 校验数据存储于 Redis(非 MySQL),防止数据库压力
协议同意规范
- 登录和注册页展示"我已阅读并同意《用户协议》《隐私政策》"
- 默认不勾选;未勾选提交时弹窗提醒并提供"一键同意并继续"
- 服务端记录
agree_at与agreement_version
安全与风控策略 — ⚪ 待开发
限流规则
- 登录:同 IP 5 次/分钟;同账号 10 次/小时
- 短信:同手机号 1 次/分钟,5 次/天
- 注册:同 IP 3 次/小时
- 密码重置:同账号 3 次/天
分级响应
- L1 轻度异常:提升验证码难度
- L2 中度异常:账号/IP/设备短期限流
- L3 重度异常:冻结高风险动作并触发人机复核
- L4 确认恶意:自动拉黑并进入观察名单
防攻击要求
- 防撞库:统一错误提示,不暴露账号存在性
- 防暴力破解:连续 5 次密码错误锁定 30 分钟
- 防重放:SSO 一次性状态值 + 回调校验
- 会话安全:Access Token 2h,Refresh Token 7d,支持轮换与吊销
Token 存储方案
- Access Token 通过
httpOnly、Secure、SameSite=StrictCookie 下发,前端不可通过 JS 读取,防止 XSS 窃取 - Refresh Token 同样存储在
httpOnlyCookie 中,路径限制为/api/auth/refresh - 禁止将 Token 存储在
localStorage或sessionStorage
当前实现差异:
userStore当前将 Token 存储在localStorage中,需在后端 Cookie 方案就绪后迁移。
退出登录范围
- 常规退出(F1.5 下拉菜单"退出登录"):仅使当前设备的 Access Token 和 Refresh Token 失效
- 全部退出(F1.9 会话管理"退出所有设备"):使账号下所有会话 Token 失效
- 密码重置(F1.3)和账号锁定触发时:自动使所有会话 Token 失效
已开发代码索引
供研发快速定位已有实现,避免重复开发。
| 文件路径 | 职责 |
|---|---|
src/views/login/LoginView.vue |
登录主页面:左右分屏、视图切换(login/register/forgot)、主题切换 |
src/views/login/components/LoginTabPanel.vue |
账号登录 + 短信登录标签页、自动登录勾选 |
src/views/login/components/RegisterPanel.vue |
注册表单 UI |
src/views/login/components/ForgotPanel.vue |
忘记密码表单 UI |
src/views/login/components/ThirdPartyLogin.vue |
微信/QQ 第三方登录入口 UI |
src/views/login/components/LoginBanner.vue |
左侧品牌展示区 |
src/views/login/composables/useLoginForms.ts |
表单状态和提交逻辑(账号登录已联调,其余为占位) |
src/components/ui/AppInput.vue |
通用输入框(含密码明文切换) |
src/components/auth/useCaptchaSlider.ts |
拼图滑块验证码核心逻辑(拖拽、对齐检测、验证提交) |
src/api/auth.ts |
认证 API(login / logout / refresh / getProfile / updateProfile / captcha) |
src/stores/user.ts |
用户状态管理(token / userInfo / login / logout) |
src/router/index.ts |
路由守卫(未登录 → /login?redirect=xxx) |
src/components/layout/AppNavbar.vue |
导航栏(登录态展示昵称,未登录展示登录链接) |
分阶段落地建议
- Phase A(P0):短信登录对接、注册对接、忘记密码对接、图形验证码、协议勾选、注册补昵称/密码强度
- Phase B(P0):企业 SSO 桥接、账号映射与直达登录
- Phase C(P0/P1):风控引擎、自动拉黑、安全后台、Token 存储迁移至 httpOnly Cookie
- Phase D(P1):个人中心下拉菜单、退出登录、OAuth 对接、多端会话管理、监控告警
验收指标
- 正常用户登录成功率 ≥ 98%
- 短信接口恶意触发量按周下降
- 企业用户无感登录成功率持续提升且不影响外部用户路径
- 协议同意和风控决策具备可审计追溯能力
最后更新: 2026-03-04