Browse Source

perf: 登录逻辑添加人机验证和图片验证码验证

BaiLuoYan 6 ngày trước cách đây
mục cha
commit
d92e789c17
1 tập tin đã thay đổi với 68 bổ sung3 xóa
  1. 68 3
      README.md

+ 68 - 3
README.md

@@ -422,8 +422,12 @@ flowchart LR
 | **认证接口** | | |
 | 用户注销 (logout) | 已登录即可 | 递增 tokenVersion,所有已签发令牌即时失效 |
 | **公开接口** | | |
-| 产品端登录 (login) | 无需鉴权 | 超级管理员被拒绝,productCode 必传 |
-| 管理后台登录 (adminLogin) | 无需鉴权 | 需验证 managementKey,限流在 managementKey 校验之后 |
+| 产品端登录 (login) | 无需鉴权 | cap.js 未启用时需携带图片验证码;超级管理员被拒绝,productCode 必传 |
+| 产品端 cap.js 登录 (user/login/cap) | 无需鉴权 | cap.js 必须已启用;提交 cap token 完成人机验证后登录 |
+| 管理后台登录 (adminLogin) | 无需鉴权 | cap.js 未启用时需携带图片验证码;需验证 managementKey |
+| 管理后台 cap.js 登录 (adminLogin/cap) | 无需鉴权 | cap.js 必须已启用;提交 cap token 完成人机验证后登录 |
+| 获取图片验证码 (captcha/get) | 无需鉴权 | cap.js 未启用时前端调用此接口展示图片验证码 |
+| 获取 cap.js 端点 (capjs/endpoint) | 无需鉴权 | 返回 cap.js 端点 URL;空串代表 cap.js 未启用,前端降级为图片验证码 |
 | 刷新令牌 | 无需鉴权 | 令牌轮转:旧令牌即时失效,返回全新令牌对;产品禁用时拒绝 |
 | 同步权限 | 无需鉴权 | 通过 appKey/appSecret 认证 |
 
@@ -755,6 +759,25 @@ Content-Type: application/json
 
 ### 公开接口(无需鉴权)
 
+#### POST /api/captcha/get — 获取图片验证码
+
+生成一张数字图片验证码,返回验证码 ID 和 Base64 编码的图片数据。仅在 cap.js **未启用**时使用,前端应先调用 `/api/capjs/endpoint` 判断当前验证方式。
+
+| 字段 | 类型 | 必填 | 说明 |
+| ------ | ------ | ------ | ------ |
+| width | int | 否 | 图片宽度(像素),默认 240 |
+| height | int | 否 | 图片高度(像素),默认 80 |
+
+**响应 data:** `{"id": "xxx", "base64image": "data:image/png;base64,..."}`
+
+#### POST /api/capjs/endpoint — 获取 cap.js 端点 URL
+
+返回 cap.js 人机验证服务的前端接入地址。前端应在展示登录页前调用此接口,据返回值决定显示图片验证码还是 cap.js 挂件。
+
+无请求参数。
+
+**响应 data:** `{"data": "https://cap.example.com/sitekey/"}` 或 `{"data": ""}` (空串表示 cap.js 未启用,降级为图片验证码)
+
 #### POST /api/auth/login — 产品端登录
 
 产品终端用户的统一登录入口。用户通过用户名密码 + 产品编码登录指定产品,登录成功后获得 JWT 令牌对和该用户在此产品下的权限列表。
@@ -771,12 +794,15 @@ Content-Type: application/json
 - 产品必须处于启用状态,否则拒绝登录
 - 用户必须是该产品的有效成员(`status=1`),且账号未冻结
 - 受 IP 维度限流保护,防止暴力破解;仅对已存在的用户名消耗限流配额
+- **验证机制二选一**:cap.js 启用时无需图片验证码,直接使用 `/auth/login`;cap.js 未启用时必须携带图片验证码,或改用 `/user/login/cap`(但此时 cap.js 未启用该路径也会被拒绝)
 
 | 字段 | 类型 | 必填 | 说明 |
 | ------ | ------ | ------ | ------ |
 | username | string | 是 | 登录名 |
 | password | string | 是 | 密码 |
 | productCode | string | 是 | 产品编码 |
+| captchaId | string | 条件必填 | 图片验证码 ID(cap.js 未启用时必填) |
+| captchaCode | string | 条件必填 | 图片验证码答案(cap.js 未启用时必填) |
 
 #### 响应 data
 
@@ -787,6 +813,23 @@ Content-Type: application/json
 | expires | int64 | accessToken 过期时间(Unix 时间戳,秒) |
 | userInfo | object | 用户信息(含 `perms` 权限码数组,前端据此控制菜单/按钮显隐) |
 
+#### POST /api/user/login/cap — 产品端 cap.js 登录
+
+产品端使用 cap.js 人机验证令牌登录。前端从 cap.js 挂件获得 `capToken` 后调用此接口,服务端向 cap.js 服务端验证令牌后执行与 `/auth/login` 相同的业务逻辑。
+
+**前提条件:** 服务端必须配置并启用 cap.js(`Capjs.Enable=1`),否则返回 400。
+
+**安全约束:** 与 `/auth/login` 相同,另外 cap.js 未启用时此接口直接拒绝请求,防止绕过验证。
+
+| 字段 | 类型 | 必填 | 说明 |
+| ------ | ------ | ------ | ------ |
+| username | string | 是 | 登录名 |
+| password | string | 是 | 密码 |
+| productCode | string | 是 | 产品编码 |
+| capToken | string | 是 | cap.js 前端挂件返回的验证令牌 |
+
+**响应 data:** 与 `/auth/login` 相同。
+
 #### POST /api/auth/adminLogin — 管理后台登录
 
 权限管理系统自身管理后台的登录入口。仅限超级管理员使用,必须额外提供 `managementKey` 验证身份。
@@ -801,15 +844,33 @@ Content-Type: application/json
 - 必须传入与服务端配置一致的 `managementKey`,该密钥仅管理后台前端持有,不可泄露给产品端
 - `managementKey` 校验在限流之前执行,无效密钥不会消耗限流配额,防止 DoS 攻击
 - 受 IP 维度限流保护
+- **验证机制二选一**:cap.js 启用时无需图片验证码;cap.js 未启用时必须携带图片验证码,或改用 `/auth/adminLogin/cap`
 
 | 字段 | 类型 | 必填 | 说明 |
 | ------ | ------ | ------ | ------ |
 | username | string | 是 | 登录名 |
 | password | string | 是 | 密码 |
 | managementKey | string | 是 | 管理端密钥(配置文件中的 `Auth.ManagementKey`) |
+| captchaId | string | 条件必填 | 图片验证码 ID(cap.js 未启用时必填) |
+| captchaCode | string | 条件必填 | 图片验证码答案(cap.js 未启用时必填) |
 
 **响应 data:** 与产品端登录接口相同。登录后不携带产品上下文,token 中 `productCode` 和 `perms` 为空。超管拥有所有产品的全部权限,不需要在 token 中枚举。
 
+#### POST /api/auth/adminLogin/cap — 管理后台 cap.js 登录
+
+管理后台使用 cap.js 人机验证令牌登录。与 `/auth/adminLogin` 业务逻辑相同,区别在于以 cap.js 令牌代替图片验证码完成人机验证。
+
+**前提条件:** 服务端必须配置并启用 cap.js(`Capjs.Enable=1`),否则返回 400。
+
+| 字段 | 类型 | 必填 | 说明 |
+| ------ | ------ | ------ | ------ |
+| username | string | 是 | 登录名 |
+| password | string | 是 | 密码 |
+| managementKey | string | 是 | 管理端密钥 |
+| capToken | string | 是 | cap.js 前端挂件返回的验证令牌 |
+
+**响应 data:** 与 `/auth/adminLogin` 相同。
+
 #### POST /api/auth/refreshToken — 刷新令牌
 
 使用有效的 refreshToken 换取全新的令牌对。采用**令牌轮转**策略,每次刷新后旧令牌即时失效,确保单会话安全。
@@ -1585,8 +1646,12 @@ server/
 | `Auth.RefreshExpire` | refreshToken 有效期(秒) | `604800`(7d) |
 | `Auth.ManagementKey` | 管理后台登录密钥(`/auth/adminLogin` 接口验证) | — |
 | `BehindProxy` | 是否部署在反向代理(Nginx 等)后面 | `false` |
+| `Capjs.Enable` | cap.js 人机验证开关(`1` 启用,`0` 或不配置则使用图片验证码) | `0` |
+| `Capjs.EndpointURL` | cap.js 服务地址(如 `https://cap.example.com`) | — |
+| `Capjs.Key` | cap.js site key(前端挂件加载和 siteverify 路径使用) | — |
+| `Capjs.Secret` | cap.js site secret(服务端 siteverify 验证使用,不可暴露给前端) | — |
 
-> **生产环境部署前,务必修改 `AccessSecret`、`RefreshSecret` 和 `ManagementKey` 为安全的随机字符串,并确保产品后端的本地验证密钥与 `AccessSecret` 一致。`ManagementKey` 仅管理后台前端持有,不可泄露给产品端。**
+> **生产环境部署前,务必修改 `AccessSecret`、`RefreshSecret` 和 `ManagementKey` 为安全的随机字符串,并确保产品后端的本地验证密钥与 `AccessSecret` 一致。`ManagementKey` 仅管理后台前端持有,不可泄露给产品端。启用 cap.js 时,`Capjs.Secret` 同样属于服务端私密配置,不得暴露给前端。**
 
 ### 反向代理部署