主题
认证授权 PRD
文档信息
| 项目 | 内容 |
|---|---|
| 产品名称 | PMForge - 认证授权 |
| 文档版本 | v2.0 |
| 创建日期 | 2026-09-11 |
| 最后更新 | 2026-09-24 |
| 文档状态 | 评审中 |
| 优先级 | P0 |
一、功能概述
1.1 功能定位
认证授权是 PMForge 平台的安全大门——它回答两个核心问题:"你是谁?"和"你能做什么?"。
- 认证(Authentication):验证用户身份,确保"你是你声称的那个人"。支持账号密码、手机验证码、社交账号、扫码等多种方式。
- 授权(Authorization):基于认证结果发放访问令牌(Token),控制用户在系统内能访问哪些资源、执行哪些操作。
本模块是 PMForge 所有业务功能的前置依赖——没有认证授权,用户无法进入系统,一切功能无从谈起。
1.2 目标用户
| 用户类型 | 使用场景 | 核心诉求 |
|---|---|---|
| C端用户 | 通过手机号/社交账号快速登录 | 无需记忆密码,一键登录 |
| B端企业用户 | 账号密码登录后台管理系统 | 安全可靠,支持 SSO 单点登录 |
| 系统管理员 | 管理 OAuth2 应用、社交登录配置、查看安全日志 | 灵活配置,安全可控 |
| 第三方开发者 | 通过 OAuth2 协议接入 PMForge | 标准协议,接入简单 |
1.3 业务价值
- 多方式登录:覆盖账号密码、手机验证码、社交账号、扫码等主流登录方式,兼顾安全性和便捷性
- 安全防护:密码加密存储、登录失败锁定、验证码防刷、IP 黑名单等多层防护机制
- 开放生态:标准 OAuth2 协议支持,允许第三方应用安全接入
- 审计合规:完整的登录日志和操作记录,满足安全审计和合规要求
- 多租户隔离:认证体系天然支持多租户架构,不同租户的用户数据完全隔离
1.4 功能范围
| 功能分类 | 后台管理端 | 前台用户端 | 说明 |
|---|---|---|---|
| 账号密码登录 | ✅ | ✅ | 最基础的登录方式 |
| 手机号验证码登录 | ✅ | ✅ | 免密码快速登录 |
| 社交账号登录 | ✅ | ✅ | 微信/QQ/钉钉等第三方登录 |
| 扫码登录 | ✅ | ✅ | 手机扫码登录 PC 端 |
| 用户注册 | ✅ | ✅ | 新用户自助注册 |
| 密码找回 | ✅ | ✅ | 忘记密码自助重置 |
| 修改密码 | ✅ | ✅ | 已登录状态修改密码 |
| 图形验证码 | ✅ | ✅ | 防机器人验证 |
| OAuth2 应用管理 | ✅ | ❌ | 管理第三方接入应用 |
| 社交客户端配置 | ✅ | ❌ | 配置社交平台接入参数 |
| 登录日志 | ✅ | ❌ | 查看登录安全记录 |
| 在线用户管理 | ✅ | ❌ | 查看/踢出在线用户 |
二、用户场景
2.1 用户角色
| 角色 | 描述 | 核心诉求 |
|---|---|---|
| 普通用户 | C 端个人用户 | 快速登录、安全便捷、不记密码 |
| 企业用户 | B 端租户用户 | 账号密码登录、SSO 单点登录 |
| 系统管理员 | 后台管理人员 | 管理 OAuth2 应用、配置社交登录、查看安全日志 |
| 第三方开发者 | 外部系统接入方 | 标准 OAuth2 协议接入、安全调用 API |
2.2 使用场景
场景1:企业员工账号密码登录(日常最高频)
- 用户:企业员工小王
- 场景:早上打开电脑 -> 访问 PMForge 后台 -> 输入用户名和密码 -> 拖动滑块完成验证码 -> 点击登录 -> 进入系统首页
- 期望:登录过程 < 3 秒完成;支持"记住密码"减少输入;密码输错时有明确提示
- 异常处理:密码连续输错 5 次 -> 账号锁定 30 分钟 -> 显示"账号已锁定,请 30 分钟后重试或联系管理员"
场景2:C端用户手机号验证码登录
- 用户:新用户小李
- 场景:打开 App -> 选择"手机号登录" -> 输入手机号 -> 点击"获取验证码" -> 收到 6 位数字短信 -> 输入验证码 -> 登录成功
- 期望:验证码 5 秒内收到;60 秒倒计时防重复发送;手机号未注册时自动创建账号
- 异常处理:验证码输错 3 次 -> 需要重新获取;验证码 10 分钟过期
场景3:微信社交账号一键登录
- 用户:普通用户小张
- 场景:打开登录页 -> 点击"微信登录"图标 -> 页面跳转到微信授权页 -> 扫码确认授权 -> 自动跳回 PMForge 并登录成功
- 期望:首次社交登录自动创建账号并绑定微信;已绑定用户直接登录无需二次操作
- 异常处理:微信已绑定其他账号 -> 提示"该微信已绑定账号 xxx,是否解绑?"
场景4:扫码登录(PC + 手机联动)
- 用户:企业用户小陈
- 场景:PC 端打开登录页 -> 点击"扫码登录" -> 屏幕显示二维码 -> 打开手机 App 扫码 -> 手机显示"确认在 PC 端登录?" -> 点击确认 -> PC 端自动跳转首页
- 期望:二维码 2 分钟内有效;扫码后手机端显示 PC 端设备信息以便确认
场景5:密码找回
- 用户:忘记密码的小刘
- 场景:登录页点击"忘记密码" -> 输入注册手机号 -> 获取验证码 -> 输入验证码验证身份 -> 设置新密码(8-20 位,含字母和数字) -> 修改成功 -> 跳转登录页
- 期望:整个流程 < 2 分钟完成;新密码不能与最近 3 次密码相同
场景6:第三方应用 OAuth2 接入
- 用户:第三方开发者
- 场景:在 PMForge 后台注册 OAuth2 应用 -> 获取 clientId 和 clientSecret -> 用户点击"使用 PMForge 登录" -> 跳转授权页 -> 用户同意授权 -> 回调获取 access_token -> 调用 PMForge API
- 期望:标准 OAuth2 授权码流程;access_token 有效期可配置
场景7:管理员踢出异常在线用户
- 用户:系统管理员
- 场景:收到安全告警 -> 进入在线用户管理页面 -> 发现某账号在异常 IP 登录 -> 点击"踢出" -> 该用户立即下线
- 期望:踢出后该用户 Token 立即失效;被踢出用户下次操作时提示"您的账号已被管理员强制下线"
2.3 用户故事与验收标准
| 编号 | 用户故事 | 优先级 | 验收标准 |
|---|---|---|---|
| US-01 | 作为用户,我希望用账号密码登录,以便访问我的个人数据 | P0 | 1. 支持用户名/手机号/邮箱三种账号格式登录 2. 登录成功 < 500ms 返回 Token 3. 密码错误 5 次锁定 30 分钟 4. 登录成功/失败均记录日志 |
| US-02 | 作为用户,我希望用手机号验证码登录,以便无需记忆密码 | P0 | 1. 验证码 60 秒内发送成功 2. 验证码 10 分钟有效 3. 未注册手机号自动创建账号 4. 每天最多发送 10 次验证码 |
| US-03 | 作为用户,我希望用微信/QQ 登录,以便快速注册登录 | P1 | 1. 支持微信(PC 扫码/公众号/小程序)、QQ、钉钉等 6+ 平台 2. 首次社交登录自动创建账号并绑定 3. 已绑定用户一键登录 |
| US-04 | 作为用户,我希望忘记密码时能快速找回,以便继续使用系统 | P0 | 1. 支持手机号和邮箱两种找回方式 2. 全流程 < 2 分钟完成 3. 新密码不能与最近 3 次相同 |
| US-05 | 作为管理员,我希望管理 OAuth2 应用,以便控制第三方接入 | P1 | 1. 支持 CRUD 操作 2. clientId 全局唯一 3. 支持 4 种授权类型 4. 令牌有效期可配置 |
| US-06 | 作为管理员,我希望查看登录日志,以便进行安全审计 | P1 | 1. 支持按用户、IP、时间、结果筛选 2. 支持导出 Excel 3. 记录登录类型、IP 归属地、浏览器信息 |
| US-07 | 作为用户,我希望登录时有图形验证码,以保障账号安全 | P0 | 1. 支持滑块拼图/文字点选 2. 密码错误 3 次后强制要求验证码 3. 验证码类型可配置 |
| US-08 | 作为用户,我希望支持扫码登录,以便在移动端快速登录 | P2 | 1. 二维码 2 分钟有效 2. 手机端确认后才登录 3. PC 端实时感知扫码状态 |
| US-09 | 作为管理员,我希望管理在线用户,以便处理异常会话 | P2 | 1. 展示在线用户列表(IP、设备、登录时间) 2. 支持强制踢出 3. 踢出后 Token 立即失效 |
| US-10 | 作为用户,我希望修改密码后所有设备退出登录,以保障安全 | P0 | 1. 修改密码需验证当前密码 2. 修改成功后所有设备的 Token 失效 3. 新密码不能与最近 3 次相同 |
三、功能需求
3.1 后台管理端
3.1.1 功能清单
| 功能 | 优先级 | 权限标识 | 说明 |
|---|---|---|---|
| 管理员登录 | P0 | — | 管理员账号密码登录后台 |
| OAuth2 应用管理 | P1 | system:oauth2-client:* | 管理第三方接入应用 |
| OAuth2 令牌管理 | P1 | system:oauth2-token:* | 查看/管理访问令牌 |
| 社交客户端配置 | P1 | system:social-client:* | 配置微信/钉钉等社交平台 |
| 登录日志查看 | P1 | system:login-log:query | 查看登录安全记录 |
| 在线用户管理 | P2 | system:auth:kickout | 查看/踢出在线用户 |
3.1.2 管理员登录
页面描述:
- 登录页面包含:系统 Logo、标题"PMForge 管理平台"、账号输入框、密码输入框、验证码区域、"登录"按钮
- 底部:支持"记住我"复选框、"忘记密码"链接
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 账号支持三种格式输入:用户名、手机号、邮箱,系统自动识别 |
| R-02 | 密码连续错误 5 次,锁定账号 30 分钟(锁定期间即使密码正确也无法登录) |
| R-03 | 验证码支持两种模式:滑块拼图、文字点选,可在后台配置 |
| R-04 | 首次登录或连续 3 次密码错误后,强制要求输入验证码 |
| R-05 | 登录成功/失败均自动记录登录日志(含 IP、浏览器、操作系统、登录结果) |
| R-06 | Token 默认有效期 2 小时,可通过配置调整 |
| R-07 | "记住我"功能有效期默认 7 天,可通过配置调整 |
| R-08 | 登录成功后,前端保存 Token,后续所有请求携带 Token 进行身份验证 |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 管理员登录 | POST | /admin-api/system/auth/login | 管理员登录获取 Token |
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| username | String | 是 | 用户名/手机号/邮箱 |
| password | String | 是 | 密码(前端加密传输) |
| captchaVerification | String | 是 | 验证码校验结果标识 |
| rememberMe | Boolean | 否 | 是否"记住我"(默认 false) |
返回结果:
| 字段名 | 类型 | 说明 |
|---|---|---|
| accessToken | String | 访问令牌,后续请求放入 Header Authorization: Bearer {accessToken} |
| refreshToken | String | 刷新令牌,accessToken 过期后用其换取新的 accessToken |
| expiresTime | Long | accessToken 过期时间(毫秒时间戳) |
3.1.3 OAuth2 应用管理
页面描述:
- 列表页:展示所有已注册的 OAuth2 应用,支持按应用名搜索,操作列包含编辑、删除
- 新增/编辑页:表单包含应用名称、客户端 ID、客户端密钥、授权类型(多选)、重定向 URI(支持多个)、令牌有效期等
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 客户端 ID(clientId)全局唯一,创建后不可修改 |
| R-02 | 支持 4 种 OAuth2 授权类型:授权码模式、隐藏式、密码模式、客户端凭证模式 |
| R-03 | 重定向 URI 支持配置多个,用于不同环境(开发/测试/生产) |
| R-04 | 访问令牌(access_token)有效期默认 7200 秒(2 小时),可配置 |
| R-05 | 刷新令牌(refresh_token)有效期默认 2592000 秒(30 天),可配置 |
| R-06 | 客户端密钥(clientSecret)在页面上脱敏显示,仅创建时可见完整值 |
| R-07 | 支持配置自动授权的 scope,用户无需手动确认 |
| R-08 | 删除应用前需确认无活跃令牌,否则提示"该应用下有 N 个活跃令牌,请先处理" |
数据字段:
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | String | 是 | 应用名称,如"CRM 系统" |
| clientId | String | 是 | 客户端唯一标识,创建后不可改 |
| clientSecret | String | 是 | 客户端密钥,加密存储 |
| redirectUris | String[] | 是 | 允许的重定向 URI 列表 |
| grantTypes | String[] | 是 | 授权类型列表 |
| scopes | String[] | 否 | 授权范围,如 ["user_info", "read", "write"] |
| accessTokenValiditySeconds | Integer | 是 | 访问令牌有效期(秒) |
| refreshTokenValiditySeconds | Integer | 是 | 刷新令牌有效期(秒) |
| autoApproveScopes | String[] | 否 | 自动授权无需用户确认的 scope |
| enable | Boolean | 是 | 是否启用 |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 权限标识 | 说明 |
|---|---|---|---|---|
| 获取应用列表 | GET | /admin-api/system/oauth2-client/list | system:oauth2-client:query | 获取所有应用 |
| 获取应用详情 | GET | /admin-api/system/oauth2-client/get | system:oauth2-client:query | 获取单个应用详情 |
| 创建应用 | POST | /admin-api/system/oauth2-client/create | system:oauth2-client:create | 创建 OAuth2 应用 |
| 更新应用 | PUT | /admin-api/system/oauth2-client/update | system:oauth2-client:update | 更新 OAuth2 应用 |
| 删除应用 | DELETE | /admin-api/system/oauth2-client/delete | system:oauth2-client:delete | 删除 OAuth2 应用 |
3.1.4 社交客户端配置
页面描述:
- 列表页:展示已配置的所有社交平台客户端,按平台类型分组显示
- 配置页:表单包含平台类型、应用 ID(AppID)、应用密钥(AppSecret)、回调地址、是否启用等
支持的社交平台:
| 平台 | 类型编码 | 登录方式 | 适用场景 |
|---|---|---|---|
| 微信开放平台 | 10 | PC 扫码登录 | 网站端扫码登录 |
| 微信公众号 | 11 | 公众号内授权 | 微信内 H5 页面授权 |
| 微信小程序 | 12 | 小程序登录 | 小程序内一键登录 |
| 钉钉 | 20 | 企业扫码登录 | 企业用户扫码登录 |
| 企业微信 | 21 | 企业微信扫码 | 企业微信内登录 |
| 30 | QQ 授权登录 | 个人用户 QQ 登录 | |
| 微博 | 31 | 微博授权登录 | 个人用户微博登录 |
| 飞书 | 40 | 飞书扫码登录 | 飞书企业用户登录 |
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 同一租户下,同一平台类型只能配置一个客户端 |
| R-02 | 应用密钥加密存储,页面脱敏显示 |
| R-03 | 回调地址必须是 HTTPS 协议(生产环境) |
| R-04 | 停用客户端后,该平台的社交登录入口在前台不显示 |
| R-05 | 配置完成后,需在前台社交登录区域展示对应平台图标 |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 权限标识 | 说明 |
|---|---|---|---|---|
| 获取社交客户端列表 | GET | /admin-api/system/social-client/list | system:social-client:query | 获取配置列表 |
| 创建社交客户端 | POST | /admin-api/system/social-client/create | system:social-client:create | 新增配置 |
| 更新社交客户端 | PUT | /admin-api/system/social-client/update | system:social-client:update | 修改配置 |
| 删除社交客户端 | DELETE | /admin-api/system/social-client/delete | system:social-client:delete | 删除配置 |
3.1.5 登录日志
登录日志的详细设计请参见 01-08-日志审计.md 中的"登录日志"章节。此处仅描述与认证授权模块的关联关系。
关联说明:
- 每次登录成功/失败时,认证模块自动调用日志模块写入登录日志
- 日志记录包含:登录方式(账号密码/手机验证码/社交登录/扫码登录)、登录 IP、浏览器信息、登录结果
- 管理员可在日志审计模块统一查看所有登录日志
3.1.6 在线用户管理
页面描述:
- 列表页:展示当前所有在线用户的会话信息
- 列表字段:会话编号、用户名、部门、登录 IP、登录地点、浏览器、操作系统、登录时间、最后活跃时间
- 操作列:强制踢出
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 在线用户数据从 Redis 中实时读取,反映当前活跃会话 |
| R-02 | 同一用户可能在多个设备同时在线(如 PC + 手机),显示为多条记录 |
| R-03 | 踢出用户后,该会话的 Token 立即失效,用户下次操作时提示"您已被强制下线" |
| R-04 | 踢出操作记录操作日志,包含操作人和被踢出的用户信息 |
| R-05 | 最后活跃时间超过 Token 有效期的记录自动消失(会话过期) |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 权限标识 | 说明 |
|---|---|---|---|---|
| 获取在线用户列表 | GET | /admin-api/system/auth/get-online-session | system:auth:kickout | 获取在线用户 |
| 踢出用户 | POST | /admin-api/system/auth/logout-by-session-id | system:auth:kickout | 强制踢出指定会话 |
3.2 前台用户端
3.2.1 功能清单
| 功能 | 优先级 | 说明 |
|---|---|---|
| 账号密码登录 | P0 | 用户名/手机号/邮箱 + 密码 |
| 手机号验证码登录 | P0 | 手机号 + 短信验证码,免密码 |
| 社交登录 | P1 | 微信/QQ/钉钉等第三方登录 |
| 扫码登录 | P2 | 手机 App 扫码登录 PC 端 |
| 用户注册 | P0 | 新用户自助注册账号 |
| 忘记密码 | P0 | 通过手机/邮箱自助重置密码 |
| 修改密码 | P0 | 已登录状态修改密码 |
| 退出登录 | P0 | 退出当前账号 |
3.2.2 账号密码登录
页面描述:
- 登录页布局:顶部系统 Logo + 标题,中间表单区域(账号输入框、密码输入框、验证码区域、登录按钮),底部社交登录图标 + 注册链接 + 忘记密码链接
- 支持切换登录方式:Tab 切换"账号登录"和"手机号登录"
交互流程:
1. 用户输入账号(用户名/手机号/邮箱均可)
2. 用户输入密码
3. 判断是否需要验证码:
- 首次登录 或 连续密码错误 >= 3 次 -> 显示验证码区域
- 否则 -> 隐藏验证码区域
4. 如需验证码,用户拖动滑块完成验证
5. 点击"登录"按钮
6. 系统校验顺序:
a. 验证码是否正确(如需要)
b. 账号是否存在
c. 账号是否被锁定(密码错误 >= 5 次)
d. 账号是否被禁用
e. 密码是否正确
7. 校验通过 -> 保存 Token 到本地 -> 跳转首页或来源页
8. 校验失败 -> 显示对应错误提示 -> 记录失败次数业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 账号支持三种格式:用户名(4-30 位字母数字)、手机号(11 位)、邮箱 |
| R-02 | 密码连续错误 5 次,锁定 30 分钟。锁定期间提示"账号已锁定,请 30 分钟后重试" |
| R-03 | 验证码在密码错误 3 次后强制出现,防止暴力破解 |
| R-04 | "记住我"有效期默认 7 天,勾选后 7 天内无需重新登录 |
| R-05 | 登录成功后跳转至用户之前访问的页面(来源页),若无来源页则跳转首页 |
| R-06 | 租户过期(expireTime < 当前时间)时,该租户所有用户无法登录,提示"您的租户已过期,请联系管理员" |
3.2.3 手机号验证码登录
页面描述:
- 登录页:手机号输入框、验证码输入框 + "获取验证码"按钮、登录按钮
- 底部:切换"账号密码登录"、社交登录图标、注册链接
交互流程:
1. 用户输入手机号
2. 前端校验手机号格式(11 位数字)
3. 点击"获取验证码"
4. 按钮变为 60 秒倒计时,不可重复点击
5. 用户收到短信验证码(6 位数字)
6. 输入验证码
7. 点击"登录"
8. 系统校验:
a. 手机号格式是否正确
b. 验证码是否正确且在有效期内
c. 该手机号是否已注册
- 已注册 -> 直接登录
- 未注册 -> 自动创建账号并登录
9. 登录成功 -> 保存 Token -> 跳转首页业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 手机号格式校验:11 位数字,1 开头 |
| R-02 | 验证码为 6 位数字 |
| R-03 | 验证码有效期 10 分钟,过期需重新获取 |
| R-04 | 60 秒内只能发送一次验证码(前端倒计时 + 后端频率限制) |
| R-05 | 每个手机号每天最多发送 10 次验证码 |
| R-06 | 手机号未注册时自动创建账号(用户名默认为手机号,密码随机生成) |
| R-07 | 验证码输错 3 次后当前验证码失效,需重新获取 |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 发送短信验证码 | POST | /admin-api/system/sms-code/send | 发送验证码到手机 |
| 手机号验证码登录 | POST | /admin-api/system/auth/sms-login | 验证码登录 |
发送验证码 - 请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| mobile | String | 是 | 手机号 |
| scene | Integer | 是 | 使用场景(1-登录 2-注册 3-找回密码) |
验证码登录 - 请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| mobile | String | 是 | 手机号 |
| code | Integer | 是 | 验证码 |
返回结果(登录成功):
| 字段名 | 类型 | 说明 |
|---|---|---|
| accessToken | String | 访问令牌 |
| refreshToken | String | 刷新令牌 |
| expiresTime | Long | 过期时间(毫秒时间戳) |
3.2.4 社交登录
页面描述:
- 登录页底部展示已启用的社交平台图标(微信、QQ、钉钉等)
- 点击图标跳转到对应平台的授权页面
业务流程:
1. 用户点击"微信登录"图标
2. 前端请求后端获取微信授权 URL
3. 页面跳转到微信授权页(用户扫码或确认授权)
4. 用户在微信端确认授权
5. 微信回调 PMForge 后端,携带授权码 code
6. 后端用 code 向微信换取 access_token
7. 后端用 access_token 获取微信用户信息(openid、昵称、头像)
8. 查询该微信 openid 是否已绑定 PMForge 账号:
- 已绑定 -> 直接登录,返回 Token
- 未绑定 -> 两种处理方式:
a. 自动创建新账号并绑定(推荐)
b. 跳转到绑定已有账号页面
9. 登录成功 -> 保存 Token -> 跳转首页接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 获取社交授权 URL | GET | /admin-api/system/auth/social-authorize | 获取跳转授权页 URL |
| 社交快捷登录 | POST | /admin-api/system/auth/social-quick-login | 已绑定用户快捷登录 |
| 社交绑定 | POST | /admin-api/system/auth/social-bind | 绑定社交账号到已有账号 |
| 社交解绑 | POST | /admin-api/system/auth/social-unbind | 解绑社交账号 |
快捷登录 - 请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | Integer | 是 | 社交平台类型(10-微信 20-QQ 30-钉钉等) |
| code | String | 是 | 授权码 |
| state | String | 是 | state 防 CSRF 参数 |
3.2.5 扫码登录
页面描述:
- PC 端登录页展示二维码区域
- 二维码下方提示"打开手机 App 扫码登录"
- 二维码过期时显示"二维码已过期,点击刷新"
业务流程:
1. PC 端打开登录页,点击"扫码登录"Tab
2. 前端请求后端生成二维码(包含唯一的 qrcodeId)
3. 页面展示二维码图片
4. PC 端每 2 秒轮询检测扫码状态
5. 用户打开手机 App 扫描二维码
6. App 解析二维码中的 qrcodeId,向服务器查询状态
7. 服务器返回"待确认",App 显示确认页面(含 PC 端设备信息)
8. 用户在 App 上点击"确认登录"
9. 服务器更新状态为"已确认"
10. PC 端轮询检测到"已确认"状态,获取 Token,跳转首页状态流转:
| 状态 | 说明 | PC 端展示 |
|---|---|---|
| WAITING | 等待扫码 | 显示二维码 |
| SCANNED | 已扫码待确认 | 显示"已扫码,请在手机上确认" |
| CONFIRMED | 已确认登录 | 自动跳转首页 |
| CANCELLED | 已取消 | 显示"已取消,请重新扫码" |
| EXPIRED | 已过期 | 显示"二维码已过期,点击刷新" |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 获取扫码二维码 | GET | /admin-api/system/auth/get-qrcode | 生成二维码 |
| 检测扫码状态 | GET | /admin-api/system/auth/check-qrcode | PC 端轮询状态 |
| 确认扫码登录 | POST | /admin-api/system/auth/confirm-qrcode | App 端确认登录 |
| 取消扫码 | POST | /admin-api/system/auth/cancel-qrcode | App 端取消登录 |
获取二维码 - 返回结果:
| 字段名 | 类型 | 说明 |
|---|---|---|
| qrcodeId | String | 二维码唯一标识 |
| qrcodeUrl | String | 二维码图片 URL |
| expireTime | Long | 过期时间(秒),默认 120 秒 |
3.2.6 用户注册
页面描述:
- 注册页:手机号/邮箱输入框、验证码输入框、密码输入框、确认密码输入框、注册按钮
- 底部:"已有账号?立即登录"链接
- 可选:邀请码输入框
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 手机号和邮箱不能与已注册用户重复 |
| R-02 | 用户名可选填,4-30 位字母数字,不可与已有用户名重复 |
| R-03 | 密码强度要求:8-20 位,必须包含字母和数字 |
| R-04 | 确认密码必须与新密码一致 |
| R-05 | 注册成功后自动登录(返回 Token,跳转首页) |
| R-06 | 如开启邀请码功能,注册时必须填写有效邀请码 |
| R-07 | 注册成功自动记录登录日志(日志类型为"注册") |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 用户注册 | POST | /admin-api/system/auth/register | 新用户注册 |
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| username | String | 否 | 用户名(4-30 位字母数字) |
| mobile | String | 否 | 手机号(与邮箱二选一) |
| String | 否 | 邮箱(与手机号二选一) | |
| code | Integer | 是 | 短信/邮件验证码 |
| password | String | 是 | 密码(8-20 位,含字母和数字) |
| inviteCode | String | 否 | 邀请码(如开启邀请码功能则必填) |
3.2.7 忘记密码
页面描述:
- 分步表单:步骤 1 输入手机号/邮箱 -> 步骤 2 输入验证码 -> 步骤 3 设置新密码 -> 完成
业务流程:
1. 用户点击"忘记密码"
2. 选择找回方式:手机号 / 邮箱
3. 输入手机号或邮箱
4. 获取验证码
5. 输入验证码,点击"下一步"
6. 系统校验验证码
7. 进入"设置新密码"页面
8. 输入新密码和确认密码
9. 提交修改
10. 修改成功 -> 跳转登录页业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 手机号/邮箱必须是已注册的,否则提示"该手机号/邮箱未注册" |
| R-02 | 验证码有效期 10 分钟 |
| R-03 | 新密码不能与最近 3 次密码相同 |
| R-04 | 密码强度要求同注册(8-20 位,含字母和数字) |
| R-05 | 密码重置成功后,该用户所有设备的 Token 失效(强制重新登录) |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 校验验证码 | POST | /admin-api/system/auth/verify-code | 校验身份验证码 |
| 重置密码 | POST | /admin-api/system/auth/reset-password | 设置新密码 |
重置密码 - 请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| mobile | String | 否 | 手机号(与邮箱二选一) |
| String | 否 | 邮箱(与手机号二选一) | |
| code | Integer | 是 | 验证码 |
| password | String | 是 | 新密码 |
3.2.8 修改密码
页面描述:
- 个人中心 -> 安全设置页面
- 表单:当前密码、新密码、确认新密码
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 当前密码必须正确才能修改 |
| R-02 | 新密码不能与最近 3 次密码相同 |
| R-03 | 密码强度要求:8-20 位,包含字母和数字 |
| R-04 | 修改成功后,该用户所有设备的 Token 全部失效,需重新登录 |
| R-05 | 修改密码操作记录操作日志 |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 修改密码 | PUT | /admin-api/system/user/profile/update-password | 修改当前用户密码 |
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| oldPassword | String | 是 | 当前密码 |
| newPassword | String | 是 | 新密码 |
3.2.9 退出登录
业务规则:
| 规则编号 | 规则描述 |
|---|---|
| R-01 | 退出登录时,当前 Token 失效 |
| R-02 | 退出登录时记录登出日志(日志类型为"登出") |
| R-03 | 前端清除本地保存的 Token,跳转登录页 |
| R-04 | 退出登录不影响其他设备的会话 |
接口设计:
| 接口名称 | 请求方式 | 接口路径 | 说明 |
|---|---|---|---|
| 退出登录 | POST | /admin-api/system/auth/logout | 退出登录 |
| 刷新令牌 | POST | /admin-api/system/auth/refresh-token | 用 refreshToken 换取新的 accessToken |
四、非功能需求
4.1 性能要求
| 指标 | 要求 | 说明 |
|---|---|---|
| 登录接口响应时间 | < 500ms | 从点击登录到返回结果 |
| 验证码发送响应时间 | < 3s | 从点击发送到短信到达 |
| Token 刷新响应时间 | < 200ms | refreshToken 换取新 Token |
| 社交登录跳转时间 | < 1s | 从点击到跳转至第三方授权页 |
| 在线用户列表加载时间 | < 1s | 100 人以内在线 |
| 登录日志查询响应时间 | < 1s | 30 天内数据 |
4.2 安全要求
| 安全项 | 实现方式 | 说明 |
|---|---|---|
| 密码加密存储 | BCrypt 算法 | 不可逆加密,即使数据库泄露也无法还原密码 |
| 传输加密 | 全站 HTTPS | 防止中间人攻击 |
| 防暴力破解 | 5 次锁定 30 分钟 | 密码连续错误自动锁定 |
| 防重放攻击 | Token + 时间戳 | 每次请求携带 Token,过期失效 |
| XSS 防护 | 输入过滤 + 输出转义 | 防止恶意脚本注入 |
| CSRF 防护 | Token 验证 + state 参数 | OAuth2 流程中 state 参数防 CSRF |
| 敏感信息脱敏 | 日志中密码/手机号脱敏 | 日志中不存储明文密码,手机号中间 4 位用 * 替代 |
| Token 安全 | 短有效期 + 刷新机制 | accessToken 2 小时过期,通过 refreshToken 续期 |
| 密码历史 | 记录最近 3 次密码 | 新密码不能与历史密码重复 |
4.3 兼容性要求
| 端 | 要求 |
|---|---|
| PC 浏览器 | Chrome 80+、Firefox 75+、Safari 13+、Edge 80+ |
| 移动端浏览器 | iOS Safari 12+、Android Chrome 80+ |
| 微信内置浏览器 | 支持(公众号/小程序登录场景) |
| 小程序 | 微信基础库 2.0+ |
五、数据设计
5.1 数据模型
5.1.1 用户表(system_users)
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT | PK, AUTO_INCREMENT | 用户编号 |
| username | VARCHAR(30) | NOT NULL | 用户名(登录用) |
| password | VARCHAR(100) | NOT NULL | 密码(BCrypt 加密存储) |
| nickname | VARCHAR(30) | NOT NULL | 用户昵称(显示用) |
| mobile | VARCHAR(11) | - | 手机号 |
| VARCHAR(50) | - | 邮箱 | |
| avatar | VARCHAR(512) | - | 头像 URL |
| status | TINYINT | NOT NULL, DEFAULT 0 | 状态(0-正常 1-停用) |
| dept_id | BIGINT | - | 所属部门编号 |
| post_ids | VARCHAR(255) | - | 岗位编号列表(JSON 数组) |
| user_type | TINYINT | NOT NULL | 用户类型(1-会员 2-管理员) |
| login_ip | VARCHAR(50) | - | 最后登录 IP |
| login_date | DATETIME | - | 最后登录时间 |
| tenant_id | BIGINT | NOT NULL | 所属租户编号 |
| creator | VARCHAR(64) | - | 创建者 |
| create_time | DATETIME | NOT NULL | 创建时间 |
| updater | VARCHAR(64) | - | 更新者 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| deleted | BIT(1) | NOT NULL, DEFAULT 0 | 删除标记 |
索引设计:
| 索引名 | 字段 | 类型 | 说明 |
|---|---|---|---|
| uk_username | username, tenant_id | UNIQUE | 同租户下用户名唯一 |
| idx_mobile | mobile | NORMAL | 按手机号查询 |
| idx_status | status | NORMAL | 按状态筛选 |
| idx_dept_id | dept_id | NORMAL | 按部门查询 |
| idx_tenant_id | tenant_id | NORMAL | 按租户查询 |
5.1.2 登录日志表(system_login_log)
详细设计参见 01-08-日志审计.md
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT | PK, AUTO_INCREMENT | 日志编号 |
| log_type | INT | NOT NULL | 日志类型(100-登录 101-登出 200-注册) |
| trace_id | VARCHAR(64) | - | 链路追踪编号 |
| user_id | BIGINT | - | 用户编号(登录失败时可能为空) |
| user_type | TINYINT | NOT NULL | 用户类型 |
| username | VARCHAR(50) | NOT NULL | 用户账号(冗余存储) |
| result | TINYINT | NOT NULL | 登录结果 |
| user_ip | VARCHAR(50) | - | 用户 IP |
| user_agent | VARCHAR(512) | - | 浏览器 UA |
| tenant_id | BIGINT | NOT NULL | 租户编号 |
| create_time | DATETIME | NOT NULL | 创建时间 |
5.1.3 OAuth2 客户端表(system_oauth2_client)
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT | PK, AUTO_INCREMENT | 编号 |
| name | VARCHAR(128) | NOT NULL | 应用名称 |
| client_id | VARCHAR(255) | NOT NULL | 客户端 ID(唯一) |
| secret | VARCHAR(255) | NOT NULL | 客户端密钥(加密存储) |
| redirect_uris | VARCHAR(255) | NOT NULL | 重定向 URI 列表 |
| authorized_grant_types | VARCHAR(255) | NOT NULL | 授权类型列表 |
| scope | VARCHAR(255) | - | 授权范围 |
| access_token_validity_seconds | INT | NOT NULL | 访问令牌有效期(秒) |
| refresh_token_validity_seconds | INT | NOT NULL | 刷新令牌有效期(秒) |
| auto_approve_scope | VARCHAR(255) | - | 自动授权的 scope |
| enable | BIT(1) | NOT NULL, DEFAULT 1 | 是否启用 |
| tenant_id | BIGINT | NOT NULL | 租户编号 |
| creator | VARCHAR(64) | - | 创建者 |
| create_time | DATETIME | NOT NULL | 创建时间 |
| updater | VARCHAR(64) | - | 更新者 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| deleted | BIT(1) | NOT NULL, DEFAULT 0 | 删除标记 |
5.1.4 社交客户端表(system_social_client)
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT | PK, AUTO_INCREMENT | 编号 |
| name | VARCHAR(128) | NOT NULL | 应用名称 |
| social_type | INT | NOT NULL | 社交平台类型 |
| client_id | VARCHAR(255) | NOT NULL | 应用 ID(AppID) |
| client_secret | VARCHAR(255) | NOT NULL | 应用密钥(加密存储) |
| agent_id | VARCHAR(255) | - | 应用 AgentId(企业微信/钉钉需要) |
| redirect_uri | VARCHAR(255) | NOT NULL | 回调地址 |
| enable | BIT(1) | NOT NULL, DEFAULT 1 | 是否启用 |
| tenant_id | BIGINT | NOT NULL | 租户编号 |
| creator | VARCHAR(64) | - | 创建者 |
| create_time | DATETIME | NOT NULL | 创建时间 |
| updater | VARCHAR(64) | - | 更新者 |
| update_time | DATETIME | NOT NULL | 更新时间 |
| deleted | BIT(1) | NOT NULL, DEFAULT 0 | 删除标记 |
5.2 数据字典
| 字典类型编码 | 字典名称 | 字典数据项 |
|---|---|---|
| system_user_type | 用户类型 | 1-会员, 2-管理员 |
| system_login_type | 登录类型 | 10-账号密码, 20-手机验证码, 30-社交登录, 40-扫码登录 |
| system_login_result | 登录结果 | 0-成功, 10-账号密码错误, 11-验证码错误, 20-用户被禁用, 30-IP 黑名单 |
| system_social_type | 社交平台类型 | 10-微信, 20-QQ, 30-微博, 40-钉钉, 50-企业微信, 60-飞书 |
| system_oauth2_grant_type | OAuth2 授权类型 | authorization_code-授权码, implicit-隐藏式, password-密码式, client_credentials-客户端凭证 |
| common_status | 通用状态 | 0-开启, 1-关闭 |
六、跨模块联动
6.1 与用户管理模块的联动
| 联动场景 | 触发条件 | 联动行为 |
|---|---|---|
| 登录时加载用户信息 | 用户登录成功 | 从用户管理模块获取用户详情(昵称、头像、部门、角色),写入 Token 扩展信息 |
| 用户被禁用 | 管理员在用户管理中禁用某用户 | 该用户所有在线 Token 立即失效,下次登录提示"账号已被禁用" |
| 密码重置 | 管理员在用户管理中重置用户密码 | 该用户所有 Token 失效,需重新登录 |
| 手机号验证码 | 验证码登录/注册/找回密码 | 调用消息通知模块的短信发送能力 |
6.2 与租户管理模块的联动
| 联动场景 | 触发条件 | 联动行为 |
|---|---|---|
| 租户过期 | 租户 expireTime < 当前时间 | 该租户所有用户无法登录,提示"租户已过期" |
| 租户停用 | 管理员停用某租户 | 该租户所有用户 Token 立即失效 |
| 租户识别 | 用户登录时 | 根据请求头 tenant-id 或域名识别所属租户,确保数据隔离 |
6.3 与日志审计模块的联动
| 联动场景 | 触发条件 | 联动行为 |
|---|---|---|
| 登录日志 | 登录成功/失败/登出/注册 | 自动写入登录日志(含登录方式、IP、浏览器、结果) |
| 操作日志 | 管理员踢出用户、修改 OAuth2 配置 | 自动写入操作日志 |
6.4 与消息通知模块的联动
| 联动场景 | 触发条件 | 联动行为 |
|---|---|---|
| 短信验证码 | 手机号验证码登录/注册/找回密码 | 调用短信发送接口发送验证码 |
| 邮件验证码 | 邮箱找回密码 | 调用邮件发送接口发送验证码 |
| 异地登录通知 | 检测到异地登录(安全审计模块触发) | 发送站内信/邮件通知用户 |
6.5 与角色权限模块的联动
| 联动场景 | 触发条件 | 联动行为 |
|---|---|---|
| 登录后加载权限 | 用户登录成功 | 从角色权限模块获取用户角色列表和权限标识列表,写入 Token |
| 动态路由 | 前端加载菜单 | 根据 Token 中的权限信息,从角色权限模块获取可访问菜单树 |
| 接口鉴权 | 每次 API 请求 | 解析 Token 中的权限标识,校验是否有权访问该接口 |
七、附录
7.1 名词解释
| 术语 | 英文 | 解释 |
|---|---|---|
| 认证 | Authentication | 验证"你是谁"的过程。比如输入账号密码,系统确认你确实是你声称的那个人 |
| 授权 | Authorization | 验证"你能做什么"的过程。认证通过后,系统根据你的角色和权限决定你能访问哪些功能 |
| Token(令牌) | Token | 登录成功后系统发放的一张"通行证",后续每次操作都出示这张通行证来证明身份,无需重复输入密码 |
| Access Token | Access Token | 访问令牌,有效期较短(默认 2 小时),用于日常 API 请求的身份验证 |
| Refresh Token | Refresh Token | 刷新令牌,有效期较长(默认 30 天),当 Access Token 过期后用它换取新的 Access Token,用户无需重新登录 |
| OAuth2 | OAuth 2.0 | 一种行业标准的授权协议,允许第三方应用在不暴露密码的情况下获取用户在系统中的有限授权 |
| SSO(单点登录) | Single Sign-On | 一处登录、多处可用。比如登录了 PMForge 后台,就不需要再单独登录关联的 CRM 系统 |
| BCrypt | BCrypt | 一种密码加密算法,特点是加密过程故意设计得很慢(相比普通加密),让黑客即使拿到数据库也无法快速暴力破解密码 |
| 验证码 | CAPTCHA | 一种区分"人"和"机器人"的验证机制。PMForge 支持滑块拼图和文字点选两种形式 |
| 客户端 | Client | 在 OAuth2 语境中,指接入 PMForge 的第三方应用(如 CRM 系统),不是指浏览器 |
| 授权码 | Authorization Code | OAuth2 授权码模式中的一种临时凭证,第三方应用用它来换取 Access Token |
| 社交登录 | Social Login | 通过微信、QQ、钉钉等第三方社交平台的账号来登录系统,无需单独注册 |
| 扫码登录 | QR Code Login | 用手机 App 扫描 PC 端展示的二维码来登录 PC 端,本质是手机端已登录的用户"授权"PC 端登录 |
| 会话 | Session | 用户从登录到退出之间的整个交互过程。一个会话对应一个活跃的 Token |
| 锁定 | Account Lockout | 密码连续错误多次后,系统自动暂时禁止该账号登录的安全措施 |
| 多租户 | Multi-Tenant | 一套系统同时服务多个独立的组织(租户),各租户数据互相隔离 |
7.2 接口汇总
| 序号 | 接口名称 | 方法 | 路径 | 端 | 优先级 |
|---|---|---|---|---|---|
| 1 | 管理员登录 | POST | /admin-api/system/auth/login | 后台 | P0 |
| 2 | 手机号验证码登录 | POST | /admin-api/system/auth/sms-login | 前台 | P0 |
| 3 | 发送短信验证码 | POST | /admin-api/system/sms-code/send | 前台 | P0 |
| 4 | 社交快捷登录 | POST | /admin-api/system/auth/social-quick-login | 前台 | P1 |
| 5 | 获取社交授权 URL | GET | /admin-api/system/auth/social-authorize | 前台 | P1 |
| 6 | 社交绑定 | POST | /admin-api/system/auth/social-bind | 前台 | P1 |
| 7 | 社交解绑 | POST | /admin-api/system/auth/social-unbind | 前台 | P1 |
| 8 | 获取扫码二维码 | GET | /admin-api/system/auth/get-qrcode | 前台 | P2 |
| 9 | 检测扫码状态 | GET | /admin-api/system/auth/check-qrcode | 前台 | P2 |
| 10 | 确认扫码登录 | POST | /admin-api/system/auth/confirm-qrcode | 前台 | P2 |
| 11 | 取消扫码 | POST | /admin-api/system/auth/cancel-qrcode | 前台 | P2 |
| 12 | 用户注册 | POST | /admin-api/system/auth/register | 前台 | P0 |
| 13 | 校验验证码 | POST | /admin-api/system/auth/verify-code | 前台 | P0 |
| 14 | 重置密码 | POST | /admin-api/system/auth/reset-password | 前台 | P0 |
| 15 | 修改密码 | PUT | /admin-api/system/user/profile/update-password | 前台 | P0 |
| 16 | 退出登录 | POST | /admin-api/system/auth/logout | 通用 | P0 |
| 17 | 刷新令牌 | POST | /admin-api/system/auth/refresh-token | 通用 | P0 |
| 18 | 获取在线用户列表 | GET | /admin-api/system/auth/get-online-session | 后台 | P2 |
| 19 | 踢出用户 | POST | /admin-api/system/auth/logout-by-session-id | 后台 | P2 |
| 20 | OAuth2 应用列表 | GET | /admin-api/system/oauth2-client/list | 后台 | P1 |
| 21 | 创建 OAuth2 应用 | POST | /admin-api/system/oauth2-client/create | 后台 | P1 |
| 22 | 更新 OAuth2 应用 | PUT | /admin-api/system/oauth2-client/update | 后台 | P1 |
| 23 | 删除 OAuth2 应用 | DELETE | /admin-api/system/oauth2-client/delete | 后台 | P1 |
| 24 | 社交客户端列表 | GET | /admin-api/system/social-client/list | 后台 | P1 |
| 25 | 创建社交客户端 | POST | /admin-api/system/social-client/create | 后台 | P1 |
| 26 | 更新社交客户端 | PUT | /admin-api/system/social-client/update | 后台 | P1 |
| 27 | 删除社交客户端 | DELETE | /admin-api/system/social-client/delete | 后台 | P1 |
7.3 变更记录
| 版本 | 日期 | 修改内容 | 修改人 |
|---|---|---|---|
| v1.0 | 2026-09-11 | 初始版本 | PM Team |
| v2.0 | 2026-09-19 | 全面重写:增强业务场景描述、验收标准、跨模块联动、名词解释 | PM Team |
本文档为认证授权模块 PRD,如有问题请联系产品负责人。