feat: 添加后台登录验证码、记住密码功能,优化媒体资源与前端规范

- 新增后台登录图形验证码功能,完善登录安全防护
- 新增登录rememberMe参数,控制Refresh Token的会话持久化策略
- 实现OSS私有桶媒体URL自动签名,统一处理图片资源的临时访问签名
- 新增素材库数据库表与上传API,规范媒体资源管理流程
- 统一前端UI图标使用@element-plus/icons-vue,重构布局图标组件
- 登录页新增验证码输入、刷新功能,添加账号记忆与记住密码逻辑
- 更新全套文档,补充API契约、技术决策记录与集成流程说明
- 修复多个业务页面的图标展示问题,新增认证流程相关测试用例
This commit is contained in:
duanshuwen
2026-08-27 07:50:59 +08:00
parent 2c8c327de7
commit 6245159e7c
35 changed files with 914 additions and 79 deletions

View File

@@ -15,17 +15,25 @@
## 通用约定
- API 前缀:`/api/admin`。
- 除登录接口外均需 `Authorization: Bearer <admin-jwt>`。
- 验证码和登录接口不要求 `Authorization`;其余受保护 Admin API 使用 `Authorization: Bearer <admin-jwt>` 或认证 Cookie 约定。
- JSON 请求统一使用 camelCase 字段。
- 变更接口写入审计日志后再提交事务。
- 成功业务结果统一放在 `data`;创建成功为 HTTP/code `201`。
- 失败统一返回数字 `code`、用户可读 `msg`、`data: null`,业务错误码放在可选的 `errorCode`。
- 所有持久化资源的 `id` 由后端生成稳定 UUID 字符串。Admin UI 必须保存并复用接口返回的 ID,不能根据标题、文案或数组下标自行拼接,也不能假设 ID 是可读 slug。
## 管理端图标约定
- `WonderQ-Admin-UI-Vue` 的界面图标统一使用 `@element-plus/icons-vue`,不新增手写 SVG、Emoji 或其他图标库。
- `src/components/layout/LayoutIcon.vue` 是后端菜单图标名与 Element Plus 图标组件之间的受控白名单适配器;未知图标必须回退为默认菜单图标,不能动态执行组件路径。
- 为兼容既有菜单数据,`Route`、`Chevron` 等 WonderQ 图标名继续保留为前端语义别名,分别映射到 Element Plus 的 `Guide`、`ArrowDown`。
- `ConciergeDetail.icon` 等业务字段属于内容数据,不是管理端界面图标;其值和接口契约不因本规范改变。
## 接口清单
| 方法 | 路径 | 用途 |
| -------- | ----------------------------------------- | -------------------- |
| `GET` | `/api/admin/auth/captcha` | 获取后台登录图形验证码 |
| `POST` | `/api/admin/auth/login` | 后台登录 |
| `POST` | `/api/admin/auth/refresh` | 使用 HttpOnly Cookie 刷新后台访问令牌 |
| `POST` | `/api/admin/auth/logout` | 撤销当前后台会话 |
@@ -70,6 +78,8 @@
| `GET` | `/api/admin/media-assets` | 素材列表 |
| `POST` | `/api/admin/media-assets/upload` | 上传图片 |
媒体上传成功响应中的 `data.url` 是可直接用于图片回显的 HTTP(S) URL。OSS 私有读场景下,该 URL 会包含短时 GET 签名;管理端应直接使用返回值,后续 Admin/Public API 响应会重新生成签名。该接口只写入素材库,不会自动绑定首页配置;绑定首页轮播或用车卡片后,仍需提交对应的站点配置保存接口。
## 站点模块
`SiteModule` 只允许以下值:
@@ -102,9 +112,34 @@ type SiteModule =
`POST /api/admin/auth/login` 请求:
```json
{ "email": "admin@example.test", "password": "<password>" }
{
"email": "admin@example.test",
"password": "<password>",
"captchaId": "<captcha-id>",
"captchaCode": "ABCD",
"rememberMe": false
}
```
登录前先调用 `GET /api/admin/auth/captcha`,接口返回:
```json
{
"code": 200,
"msg": "success",
"data": {
"captchaEnabled": true,
"captchaId": "<captcha-id>",
"image": "data:image/svg+xml;base64,<image-data>",
"expiresIn": 120
}
}
```
验证码只允许消费一次,默认 120 秒过期。验证码答案只以哈希形式保存在 Redis 中;验证码错误、过期或重复使用时登录返回 `401`,管理端应重新获取验证码。验证码接口和登录接口都依赖 Redis,Redis 不可用时返回 `503`,不得绕过验证码或会话校验。
`rememberMe` 默认为 `false`。勾选后,Refresh Token Cookie 按现有 7 天有效期持久化,刷新令牌轮换时继续保持持久化;未勾选时使用会话级 HttpOnly Cookie,刷新时不延长为持久化 Cookie。该字段只控制登录会话生命周期,不表示服务端或前端保存密码。
成功响应包裹为 `data: { token, accessToken, expiresIn, user: { id, email, name, role } }`。`accessToken` 是短时访问令牌,`token` 是当前响应中的同值兼容字段;Refresh Token 只通过同域 HttpOnly Cookie 返回,不进入 JSON。
管理员登录、刷新和退出依赖 Redis 会话存储。Refresh Token 轮换后旧令牌立即失效;Redis 不可用时认证接口返回 `503`,不降级为无会话校验。