950 lines
57 KiB
Markdown
950 lines
57 KiB
Markdown
# ephron.ren 功能测试计划
|
||
|
||
**版本**: v4.0
|
||
**日期**: 2026-05-03
|
||
**站点**: https://www.ephron.ren/
|
||
**仓库**: https://gitea.ephron.ren/ephron_ren/ephron.ren
|
||
|
||
---
|
||
|
||
## 一、测试概览
|
||
|
||
### 1.1 服务架构
|
||
|
||
| 服务 | 地址 | 本地端口 | 说明 |
|
||
|------|------|----------|------|
|
||
| Home | https://www.ephron.ren | 8000 | 个人主页 + 内容管理后台 |
|
||
| Auth | https://auth.ephron.ren | 8001 | 登录注册 + 用户管理 + RBAC + 审计 |
|
||
| Blog | https://blog.ephron.ren | 8002 | 博客文章 + 评论 + 点赞 + 搜索 |
|
||
| Canvas | https://canvas.ephron.ren | 8003 | AI 生成页面作品管理 |
|
||
| Prompt | https://prompt.ephron.ren | 8004 | 提示词 CRUD + 版本管理 |
|
||
|
||
### 1.2 测试账号
|
||
|
||
| 角色 | 用户名 | 密码 | 用途 |
|
||
|------|--------|------|------|
|
||
| 管理员 | Elaina_admin | Elaina2026! | 测试全部管理后台功能 |
|
||
| 普通用户 | Elaina_user | Elaina2026! | 测试前台功能 + 权限拦截 |
|
||
| 邀请码 | 7CQ0-GE9S-L6QS | - | 注册流程测试 |
|
||
|
||
### 1.3 认证机制
|
||
|
||
- 跨服务 Cookie `ephron_auth`,域 `.ephron.ren`
|
||
- RBAC 权限模型:`user`(10) < `admin`(20) < `owner`(30)
|
||
- 细粒度权限键:如 `blog.post.create_draft`、`auth.user.view_active`
|
||
|
||
### 1.4 优先级定义
|
||
|
||
| 级别 | 含义 | 说明 |
|
||
|------|------|------|
|
||
| P0 | 核心功能 | 阻塞用户使用,必须通过 |
|
||
| P1 | 重要功能 | 影响体验,应尽快修复 |
|
||
| P2 | 次要功能 | 可延后处理 |
|
||
|
||
### 1.5 测试统计
|
||
|
||
| 版本 | 测试用例数 |
|
||
|------|:----------:|
|
||
| v3.0 | 366 |
|
||
| v4.0 全量 | **453** |
|
||
|
||
---
|
||
|
||
## 二、测试用例
|
||
|
||
---
|
||
|
||
### 模块 1:Home 主页 (www.ephron.ren)
|
||
|
||
#### 1.1 公开页面
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| H-001 | 首页加载 | 访问 / | HTTP 200,正常渲染 | 无 | P0 |
|
||
| H-002 | CSS/JS/图片 | 检查所有静态资源 | 全部 200 | 无 | P0 |
|
||
| H-003 | 响应式布局 | 调整窗口宽度至 375px/768px/1440px | 布局自适应,无溢出 | 无 | P1 |
|
||
| H-004 | 导航→博客 | 点击「博客」 | 跳转 blog.ephron.ren | 无 | P0 |
|
||
| H-005 | 导航→画布 | 点击「画布」 | 跳转 canvas.ephron.ren | 无 | P0 |
|
||
| H-006 | 导航→提示词 | 点击「提示词」 | 跳转 prompt.ephron.ren | 无 | P0 |
|
||
| H-007 | 登录链接 | 未登录时点击「未登录」 | 跳转 auth.ephron.ren/login | 无 | P0 |
|
||
| H-008 | 登出链接 | 已登录时点击用户名 | 显示登出选项 | 任意 | P1 |
|
||
| H-009 | 个人信息 | 检查 hero 区域 | 显示姓名、技能标签 | 无 | P1 |
|
||
| H-010 | 联系按钮 | 点击「联系我」 | 弹出邮箱/复制功能 | 无 | P2 |
|
||
| H-011 | 备案链接 | 点击 ICP/公安备案 | 跳转官方网站 | 无 | P2 |
|
||
| H-012 | 健康检查 | 访问 /health | 返回 `{"status":"ok"}` | 无 | P2 |
|
||
|
||
#### 1.2 管理后台 (/admin)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| H-013 | Admin 首页 | 以 Elaina_admin 访问 /admin | 显示内容编辑器,含草稿/发布/丢弃功能 | 管理员 | P0 |
|
||
| H-014 | Admin 权限拦截 | 以 Elaina_user 访问 /admin | 重定向到登录页或提示权限不足 | 普通 | P0 |
|
||
| H-015 | Admin 未登录 | 未登录访问 /admin | 重定向到 auth.ephron.ren/login?redirect=... | 无 | P0 |
|
||
| H-016 | 保存草稿 | 编辑内容后 POST /admin/save | 保存成功,不影响已发布版本 | 管理员 | P0 |
|
||
| H-016a | 结构化 JSON 内容 | 编辑 experience/projects/skills 各 section | 各 section 独立保存,含 is_draft 标记 | 管理员 | P1 |
|
||
| H-016b | Service Token 拒绝 | 带 Authorization: Bearer 访问 /admin | 返回 403,审计日志记录 | 服务 | P0 |
|
||
| H-017 | 发布内容 | POST /admin/publish | 发布成功,草稿被清除 | 管理员 | P0 |
|
||
| H-018 | 丢弃草稿 | POST /admin/discard | 草稿被丢弃,已发布版本不变 | 管理员 | P1 |
|
||
| H-019 | CSRF 保护 | 不带 csrf_token 提交表单 | 返回「CSRF token 验证失败」 | 管理员 | P0 |
|
||
| H-020 | 速率限制 | 1 分钟内保存 21+ 次 | 第 21 次返回 429 | 管理员 | P1 |
|
||
| H-021 | Service Token 拦截 | 带 Authorization: Bearer *** 访问 /admin | 返回 403 | 服务 | P1 |
|
||
| H-022 | 登出 | POST /admin/logout | Cookie 清除,跳转首页 | 管理员 | P0 |
|
||
|
||
---
|
||
|
||
### 模块 2:Auth 认证服务 (auth.ephron.ren)
|
||
|
||
#### 2.1 登录页面
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-001 | 登录页加载 | 访问 /login | 200,显示用户名/密码表单 | 无 | P0 |
|
||
| A-002 | 空表单提交 | 不填写直接登录 | 浏览器原生验证拦截 | 无 | P0 |
|
||
| A-003 | 错误凭证 | 输入 wrong/wrong | 显示错误消息,不跳转 | 无 | P0 |
|
||
| A-004 | 管理员登录 | Elaina_admin / Elaina2026! | 登录成功,设置 Cookie | 管理员 | P0 |
|
||
| A-005 | 普通用户登录 | Elaina_user / Elaina2026! | 登录成功,设置 Cookie | 普通 | P0 |
|
||
| A-006 | 登录后跳转 | 带 redirect 参数登录 | 跳转到指定 URL | 任意 | P0 |
|
||
| A-007 | 登录成功页 | 不带 redirect 登录 | 跳转到 /login-success | 任意 | P1 |
|
||
| A-008 | 登录限流 | 1 分钟内 6 次错误 | 第 6 次 429 | 无 | P1 |
|
||
| A-009 | 注册链接 | 点击「立即注册」 | 跳转 /register | 无 | P0 |
|
||
| A-010 | 提示消息 | 带 message 参数访问 | 显示提示文字 | 无 | P1 |
|
||
|
||
#### 2.2 注册页面
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-011 | 注册页加载 | 访问 /register | 200,显示注册表单 | 无 | P0 |
|
||
| A-012 | 表单字段 | 检查所有字段 | 用户名/密码/确认密码/邀请码/邮箱(可选) | 无 | P0 |
|
||
| A-013 | 空表单提交 | 不填写直接注册 | 验证拦截 | 无 | P0 |
|
||
| A-014 | 密码不一致 | 输入不同密码 | 显示「两次输入的密码不一致」 | 无 | P0 |
|
||
| A-015 | 弱密码 | 输入 12345678 | 显示密码强度不足 | 无 | P0 |
|
||
| A-015a | 弱密码黑名单 | 输入常见弱密码 (password/abc123/qwerty 等) | 拒绝,提示密码过于常见 | 无 | P0 |
|
||
| A-015b | 密码复杂度 | 输入仅数字 `12345678` / 仅小写 `abcdefgh` | 拒绝,需满足 3/4 类别(大小写+数字+特殊字符) | 无 | P0 |
|
||
| A-015c | 密码长度下限 | 输入 7 位强混合密码 | 拒绝,最少 8 字符 | 无 | P0 |
|
||
| A-015d | 密码长度上限 | 输入 200 位密码 | 拒绝,最多 128 字符 | 无 | P1 |
|
||
| A-016 | 无效邀请码 | 输入错误邀请码 | 显示「邀请码无效」 | 无 | P0 |
|
||
| A-017 | 正常注册 | 使用 7CQ0-GE9S-L6QS | 注册成功,自动登录 | 无 | P0 |
|
||
| A-017a | 注册自动登录 | 注册成功后检查 Cookie | 自动设置 ephron_auth Cookie,无需再次登录 | 无 | P0 |
|
||
| A-017b | 邀请码过期 | 使用已过期的邀请码注册 | 显示「邀请码已过期」 | 无 | P0 |
|
||
| A-017c | 邀请码用尽 | 使用已达最大使用次数的邀请码 | 显示「邀请码已失效」 | 无 | P0 |
|
||
| A-018 | 用户名重复 | 使用已存在的用户名 | 显示「用户名已被使用」 | 无 | P0 |
|
||
| A-018a | 用户名黑名单 | 注册保留名 (admin/root/system/ephron 等) | 拒绝,提示用户名不可用 | 无 | P0 |
|
||
| A-018b | 用户名格式 | 输入 `1abc`(数字开头)/ `ab`(过短)/ 含特殊字符 | 验证拦截:3-20 字符,字母开头,仅字母数字下划线 | 无 | P0 |
|
||
| A-018c | 邮箱格式验证 | 输入 `invalid` / `a@` / `@b.c` | 邮箱格式错误提示 | 无 | P1 |
|
||
| A-018d | 邮箱唯一性 | 使用已注册的邮箱 | 显示「邮箱已被使用」 | 无 | P1 |
|
||
| A-019 | 用户名可用性检查 | GET /api/check-username?username=xxx | 返回 `{available: true/false}` | 无 | P1 |
|
||
| A-019a | 用户名检查限流 | 1 分钟内 21+ 次请求 | 第 21 次 429 | 无 | P1 |
|
||
| A-020 | 邀请码验证 | POST /api/verify-invite | 返回 `{valid: true/false}` | 无 | P1 |
|
||
| A-020a | 邀请码验证限流 | 1 分钟内 11+ 次请求 | 第 11 次 429 | 无 | P1 |
|
||
| A-020b | 注册限流 | 1 小时内 6 次注册 | 第 6 次 429 | 无 | P1 |
|
||
|
||
#### 2.3 登出与跨服务认证
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-021 | Auth 登出 | POST /api/logout | Cookie 清除,跳转 /login | 任意 | P0 |
|
||
| A-022 | Blog 登出 | 访问 blog.ephron.ren/logout | Cookie 清除 | 任意 | P0 |
|
||
| A-023 | Canvas 登出 | 访问 canvas.ephron.ren/logout | Cookie 清除 | 任意 | P0 |
|
||
| A-024 | Prompt 登出 | 访问 prompt.ephron.ren/logout | Cookie 清除 | 任意 | P0 |
|
||
| A-025 | Home 登出 | 访问 www.ephron.ren/logout | Cookie 清除 | 任意 | P0 |
|
||
| A-026 | 跨服务 Cookie | Auth 登录后访问 Blog | Blog 显示已登录态 | 任意 | P0 |
|
||
| A-027 | 跨服务 Cookie | Auth 登录后访问 Canvas | Canvas 显示已登录态 | 任意 | P0 |
|
||
| A-028 | 跨服务 Cookie | Auth 登录后访问 Prompt | Prompt 显示已登录态 | 任意 | P0 |
|
||
| A-029 | API 验证(已登录) | GET /api/auth/verify | 200 `{authenticated: true}` | 任意 | P0 |
|
||
| A-029a | API 验证 min_role | GET /api/auth/verify?min_role=admin | 普通用户返回 403,管理员返回 200 | 任意 | P0 |
|
||
| A-029b | 服务管理员认证 | GET /api/authz/service-admin | 管理员返回 200,普通用户返回 403 | 任意 | P1 |
|
||
| A-030 | API 验证(未登录) | GET /api/auth/verify | 401 | 无 | P0 |
|
||
|
||
#### 2.4 管理后台 — 总览 (/admin)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-031 | Admin 首页 | 以管理员访问 /admin | 显示统计面板(活跃用户数、邀请码数、近 7 天注册等) | 管理员 | P0 |
|
||
| A-031a | 统计数据准确性 | 对比 Admin 面板数据与数据库 | 活跃用户数/邀请码数/近 7 天注册数准确 | 管理员 | P1 |
|
||
| A-032 | Admin 权限拦截 | 以普通用户访问 /admin | 重定向或权限不足提示 | 普通 | P0 |
|
||
| A-033 | Admin 未登录 | 未登录访问 /admin | 重定向到 /login?redirect=/admin | 无 | P0 |
|
||
|
||
#### 2.5 管理后台 — 邀请码管理 (/admin/invites)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-034 | 邀请码列表 | 访问 /admin/invites | 显示所有邀请码,含状态、使用次数、过期时间 | 管理员 | P0 |
|
||
| A-035 | 生成邀请码 | 填写最大使用次数/过期天数/备注,提交 | 生成新邀请码,显示在列表 | 管理员 | P0 |
|
||
| A-036 | 禁用邀请码 | 点击禁用按钮 | 状态变为禁用 | 管理员 | P0 |
|
||
| A-037 | 启用邀请码 | 点击启用按钮 | 状态恢复启用 | 管理员 | P0 |
|
||
| A-038 | 删除邀请码 | 点击删除按钮 | 邀请码及使用记录被删除 | 管理员 | P1 |
|
||
| A-038a | 删除邀请码级联 | 删除有使用记录的邀请码 | 使用记录同步删除,无孤立数据 | 管理员 | P1 |
|
||
| A-039 | CSRF 保护 | 不带 csrf_token 提交 | 返回验证失败 | 管理员 | P0 |
|
||
| A-040 | 限流 | 1 分钟内生成 11+ 个 | 第 11 个 429 | 管理员 | P1 |
|
||
|
||
#### 2.6 管理后台 — 用户管理 (/admin/users)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-041 | 活跃用户列表 | 访问 /admin/users | 显示所有活跃用户 | 管理员 | P0 |
|
||
| A-042 | 已禁用用户列表 | 访问 /admin/users/disabled | 显示已禁用用户 | 管理员 | P0 |
|
||
| A-043 | 禁用用户 | 选择用户,点击禁用 | 用户状态变为禁用 | 管理员 | P0 |
|
||
| A-044 | 禁用自己 | 尝试禁用自己的账号 | 返回「不能禁用自己」 | 管理员 | P0 |
|
||
| A-045 | 启用用户 | 选择已禁用用户,点击启用 | 用户恢复活跃 | 管理员 | P0 |
|
||
| A-046 | 删除用户 | 选择已禁用用户,点击删除 | 用户被永久删除 | 管理员 | P1 |
|
||
| A-046a | 删除用户级联 | 删除有角色/登录日志/邀请码记录的用户 | 角色关联、登录日志、邀请码使用记录同步删除 | 管理员 | P1 |
|
||
| A-046b | 删除活跃用户 | 尝试删除未禁用的用户 | 拒绝,需先禁用再删除 | 管理员 | P1 |
|
||
| A-047 | 用户详情 | 点击用户名 /admin/users/{username} | 显示用户详情和角色编辑 | 管理员 | P0 |
|
||
| A-047a | 用户详情角色编辑 | 在详情页修改用户角色 | 角色更新成功,页面刷新后反映新角色 | 管理员 | P0 |
|
||
|
||
#### 2.7 管理后台 — 角色权限管理 (/admin/roles)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-048 | 角色列表 | 访问 /admin/roles | 显示所有角色及权限 | 管理员 | P0 |
|
||
| A-049 | 创建角色 | 填写 key/name/description/权限,提交 | 创建成功 | 管理员 | P0 |
|
||
| A-050 | 删除角色 | 删除自定义角色 | 删除成功(内置角色不可删) | 管理员 | P1 |
|
||
| A-051 | 分配角色 | POST /admin/users/roles/assign | 角色绑定成功 | 管理员 | P0 |
|
||
| A-052 | 移除角色 | POST /admin/users/roles/remove | 角色移除成功 | 管理员 | P0 |
|
||
| A-053 | 批量更新角色 | POST /admin/users/roles/update | 用户角色更新 | 管理员 | P1 |
|
||
| A-054 | 角色权限不足 | 普通用户访问 /admin/roles | 重定向或提示权限不足 | 普通 | P0 |
|
||
|
||
#### 2.8 管理后台 — 审计日志 (/admin/audit)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-055 | 审计日志页 | 访问 /admin/audit | 显示操作日志列表 | 管理员 | P0 |
|
||
| A-056 | 筛选功能 | 按 actor_id/service/action/time 筛选 | 返回过滤结果 | 管理员 | P1 |
|
||
| A-057 | 时间范围 | 设置 start_time/end_time | 返回该时段日志 | 管理员 | P1 |
|
||
| A-058 | 权限控制 | 普通用户访问 | 重定向或提示权限不足 | 普通 | P0 |
|
||
|
||
#### 2.9 管理后台 — 服务账号 (/admin/service-accounts)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| A-059 | 服务账号列表 | 访问 /admin/service-accounts | 显示所有服务账号 | 管理员 | P0 |
|
||
| A-060 | 创建服务账号 | 填写名称/描述,提交 | 创建成功,自动生成 key | 管理员 | P0 |
|
||
| A-061 | 生成令牌 | POST /admin/service-accounts/tokens/generate | 生成 token,显示一次 | 管理员 | P0 |
|
||
| A-062 | 吊销令牌 | 吊销已有 token | Token 失效 | 管理员 | P1 |
|
||
| A-063 | 停用服务账号 | 停用服务账号 | 账号不可用 | 管理员 | P1 |
|
||
| A-064 | 权限控制 | 普通用户访问 | 重定向或提示权限不足 | 普通 | P0 |
|
||
|
||
---
|
||
|
||
### 模块 3:Blog 博客服务 (blog.ephron.ren)
|
||
|
||
#### 3.1 公开页面
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-001 | 博客首页 | 访问 / | 200,显示最新文章 + 统计 | 无 | P0 |
|
||
| B-002 | 文章列表 | 访问 /posts | 显示所有已发布文章 | 无 | P0 |
|
||
| B-003 | 文章详情 | 点击文章 /posts/{slug} | Markdown 正确渲染,显示阅读时间、浏览量 | 无 | P0 |
|
||
| B-003a | 阅读时间估算 | 查看中文/英文文章 | 中文 300 字/分钟,英文 200 词/分钟计算 | 无 | P2 |
|
||
| B-003b | 浏览量计数 | 刷新文章详情页 | 浏览量递增(数据库记录) | 无 | P2 |
|
||
| B-003c | CRLF→LF 规范化 | 提交含 CRLF 的文章内容 | 保存后内容为 LF 换行 | 管理员 | P2 |
|
||
| B-004 | 代码高亮 | 查看含代码块的文章 | 语法高亮正常 | 无 | P1 |
|
||
| B-005 | 数学公式 | 查看含 LaTeX 的文章 | MathJax 渲染正常 | 无 | P1 |
|
||
| B-006 | 归档页 | 访问 /archive | 按年月分组显示 | 无 | P1 |
|
||
| B-007 | 标签列表 | 访问 /tags | 显示标签及数量 | 无 | P1 |
|
||
| B-008 | 按标签筛选 | 点击标签 /tags/{tag} | 显示该标签文章 | 无 | P1 |
|
||
| B-009 | RSS Feed | 访问 /feed | 有效 RSS XML | 无 | P1 |
|
||
| B-010 | Sitemap | 访问 /sitemap.xml | 有效 Sitemap XML | 无 | P2 |
|
||
| B-011 | 草稿不可见 | 未登录访问草稿 URL | 404 | 无 | P0 |
|
||
| B-011a | 草稿预览(已登录) | 管理员访问草稿 URL | 正常显示,含草稿标记 | 管理员 | P0 |
|
||
| B-012 | 草稿可见 | 管理员访问草稿 URL | 正常显示 | 管理员 | P0 |
|
||
| B-013 | 404 页面 | 访问 /posts/not-exist | 404 | 无 | P1 |
|
||
|
||
#### 3.2 搜索
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-014 | 简单搜索 | /posts?q=关键词 | 返回匹配文章 | 无 | P0 |
|
||
| B-015 | 全文搜索 | /posts?q=关键词&mode=fulltext | 返回匹配文章 + 高亮 | 无 | P1 |
|
||
| B-015a | 全文搜索中文分词 | /posts?q=关键词&mode=fulltext(中文关键词) | jieba 分词正确,返回相关结果 | 无 | P1 |
|
||
| B-015b | 搜索结果高亮 | 查看 fulltext 搜索结果 | 匹配关键词高亮显示,HTML 标签已转义 | 无 | P1 |
|
||
| B-015c | 搜索模式对比 | 同一关键词分别用 simple 和 fulltext | simple 为字符串匹配,fulltext 为 BM25 排序 | 无 | P2 |
|
||
| B-016 | 空搜索 | /posts?q= | 显示所有文章 | 无 | P1 |
|
||
| B-017 | 无结果 | 搜索不存在的词 | 空结果或提示 | 无 | P1 |
|
||
|
||
#### 3.3 评论系统
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-018 | 评论显示 | 查看文章底部 | 显示已审核评论 | 无 | P0 |
|
||
| B-019 | 提交评论(已登录) | POST /api/comments/ | 成功,提示等待审核 | 任意 | P0 |
|
||
| B-020 | 提交评论(未登录) | POST /api/comments/ | 401 | 无 | P0 |
|
||
| B-021 | 回复评论 | 带 parent_id 提交 | 创建嵌套回复 | 任意 | P2 |
|
||
| B-022 | 评论限流 | 1 分钟内 6+ 条 | 第 6 条 429 | 任意 | P1 |
|
||
|
||
#### 3.4 点赞系统
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-023 | 点赞状态 | GET /api/likes/posts/{slug} | 返回 liked + like_count | 无 | P0 |
|
||
| B-024 | 点赞 | POST /api/likes/toggle | 点赞数 +1 | 无 | P0 |
|
||
| B-025 | 取消点赞 | 再次 toggle | 点赞数 -1 | 无 | P0 |
|
||
| B-025a | 点赞统计 API | GET /api/likes/stats | 返回所有文章点赞统计 | 无 | P2 |
|
||
| B-026 | 点赞限流 | 1 分钟内 11+ 次 | 第 11 次 429 | 无 | P2 |
|
||
|
||
#### 3.5 管理后台 (/admin)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-027 | Admin 首页 | 以管理员访问 /admin | 文章列表(含草稿)+ 统计 | 管理员 | P0 |
|
||
| B-028 | 搜索文章 | 在 Admin 搜索框输入关键词 | 显示匹配结果 | 管理员 | P1 |
|
||
| B-029 | 新建文章 | /admin/new,填标题/内容/标签,提交 | 创建成功 | 管理员 | P0 |
|
||
| B-030 | 编辑文章 | /admin/edit/{slug},修改后保存 | 保存成功 | 管理员 | P0 |
|
||
| B-031 | 删除文章 | 点击删除 | 文章删除 | 管理员 | P0 |
|
||
| B-032 | 切换草稿 | 点击草稿/发布切换 | 状态切换 | 管理员 | P0 |
|
||
| B-033 | 切换置顶 | 点击置顶切换 | 置顶状态切换 | 管理员 | P1 |
|
||
| B-033a | 置顶文章排序 | 置顶文章在列表中 | 置顶文章排在非置顶之前 | 管理员 | P1 |
|
||
| B-034 | 图片上传 | 上传 jpg/png/gif/webp | 成功,返回 URL + Markdown 片段 | 管理员 | P1 |
|
||
| B-034a | 图片自动转 WebP | 上传 jpg/png 图片 | 自动转换为 WebP 格式,最大 1920x1080 | 管理员 | P1 |
|
||
| B-034b | 图片上传返回格式 | 检查上传响应 | 返回 URL、Markdown 片段、文件名、大小、尺寸 | 管理员 | P2 |
|
||
| B-035 | 图片大小限制 | 上传 >5MB 图片 | 返回错误 | 管理员 | P1 |
|
||
| B-036 | 内容大小限制 | 提交 >1MB 内容 | 返回错误 | 管理员 | P1 |
|
||
| B-037 | CSRF 保护 | 不带 csrf_token 提交 | 验证失败 | 管理员 | P0 |
|
||
| B-038 | 创建限流 | 1 分钟内创建 11+ 篇 | 第 11 篇 429 | 管理员 | P1 |
|
||
| B-039 | 保存限流 | 1 分钟内保存 21+ 次 | 第 21 次 429 | 管理员 | P1 |
|
||
| B-040 | 删除限流 | 1 分钟内删除 6+ 篇 | 第 6 篇 429 | 管理员 | P1 |
|
||
| B-041 | Admin 权限拦截 | 普通用户访问 /admin | 重定向或权限不足 | 普通 | P0 |
|
||
| B-042 | Admin 登出 | POST /admin/logout | Cookie 清除 | 管理员 | P0 |
|
||
|
||
#### 3.6 评论管理后台
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-043a | 评论管理页面 | 访问 /admin/comments | 显示评论管理 UI(审核/删除操作) | 管理员 | P0 |
|
||
| B-043b | 评论分页 | 评论超过单页时 | 分页控件正常 | 管理员 | P1 |
|
||
|
||
#### 3.6.1 评论管理 API
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
| B-043 | 全部评论 | GET /api/comments/admin/all | 返回评论列表(含未审核) | 管理员 | P0 |
|
||
| B-044 | 待审核评论 | GET /api/comments/admin/pending | 返回待审核列表 | 管理员 | P0 |
|
||
| B-045 | 审核通过 | POST /api/comments/admin/{id}/approve | 评论变为已审核 | 管理员 | P0 |
|
||
| B-046 | 删除评论 | DELETE /api/comments/admin/{id} | 评论被删除 | 管理员 | P0 |
|
||
| B-047 | 评论详情 | GET /api/comments/admin/{id} | 返回含 IP 等敏感信息 | 管理员 | P1 |
|
||
| B-048 | 权限拦截 | 普通用户访问 admin API | 403 | 普通 | P0 |
|
||
|
||
#### 3.7 Service API
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| B-049 | 列表草稿 | GET /api/service/posts | 可管理的草稿列表 | 服务 | P1 |
|
||
| B-049a | 所有权隔离 | 服务 A 创建的草稿,服务 B 尝试访问 | 403 或 404 | 服务 | P0 |
|
||
| B-049b | 人工接管 | 服务创建的草稿,管理员编辑 | 编辑成功,ownership_type 保持 service | 管理员 | P1 |
|
||
| B-050 | 创建草稿 | POST /api/service/posts | 成功,返回 slug | 服务 | P1 |
|
||
| B-051 | 更新草稿 | PATCH /api/service/posts/{slug} | 成功 | 服务 | P1 |
|
||
| B-052 | 删除草稿 | DELETE /api/service/posts/{slug} | 成功 | 服务 | P1 |
|
||
| B-053 | 无 token | 不带 Authorization | 401 | 无 | P1 |
|
||
| B-054 | 非拥有者 | 访问他人草稿 | 403 | 服务 | P1 |
|
||
|
||
---
|
||
|
||
### 模块 4:Canvas 画布服务 (canvas.ephron.ren)
|
||
|
||
#### 4.1 公开页面
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| C-001 | 首页加载 | 访问 / | 200,显示 Canvas 列表 | 无 | P0 |
|
||
| C-002 | 分类筛选 | 点击分类标签 | 按分类显示 | 无 | P1 |
|
||
| C-003 | 搜索 | 输入关键词 | 返回匹配结果 | 无 | P1 |
|
||
| C-004 | 预览页 | 访问 /view/{slug} | iframe 加载 Canvas 内容 | 无 | P0 |
|
||
| C-005 | 原始 HTML | 访问 /raw/{slug} | 返回原始 HTML | 无 | P0 |
|
||
| C-005a | 原始 HTML 安全 | /raw/{slug} 响应头检查 | Content-Type 为 text/html,有 CSP 限制 | 无 | P0 |
|
||
| C-006 | 访问计数 | POST /api/view/{slug} | 计数递增(AJAX 请求) | 无 | P1 |
|
||
| C-007 | 草稿不可见 | 未登录访问草稿 | 404 | 无 | P0 |
|
||
| C-008 | 空状态 | 无 Canvas 时 | 显示「还没有工具」 | 无 | P1 |
|
||
|
||
#### 4.2 管理后台 (/admin)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| C-009 | Admin 首页 | 以管理员访问 /admin | 显示所有 Canvas(含草稿)+ 统计 | 管理员 | P0 |
|
||
| C-010 | 搜索 | 在 Admin 搜索 | 显示匹配结果 | 管理员 | P1 |
|
||
| C-011 | 新建 Canvas | /admin/new,填标题/slug/内容/分类,提交 | 创建成功 | 管理员 | P0 |
|
||
| C-011a | 用户指定 slug | 创建时自定义 slug | slug 保存成功,可通过自定义 slug 访问 | 管理员 | P1 |
|
||
| C-011b | slug 格式验证 | 输入大写/特殊字符/中文 slug | 拒绝,仅允许小写字母数字下划线连字符 | 管理员 | P0 |
|
||
| C-011c | 分类/来源字段 | 选择预定义分类和来源 | 正确保存并显示 | 管理员 | P1 |
|
||
| C-012 | 编辑 Canvas | /admin/edit/{slug},修改后保存 | 保存成功 | 管理员 | P0 |
|
||
| C-013 | 删除 Canvas | POST /admin/delete | 删除成功 | 管理员 | P0 |
|
||
| C-014 | 切换草稿 | POST /admin/toggle-draft | 状态切换 | 管理员 | P0 |
|
||
| C-015 | CSRF 保护 | 不带 csrf_token 提交 | 验证失败 | 管理员 | P0 |
|
||
| C-016 | 创建限流 | 1 分钟内 11+ 个 | 第 11 个 429 | 管理员 | P1 |
|
||
| C-017 | 保存限流 | 1 分钟内 21+ 次 | 第 21 次 429 | 管理员 | P1 |
|
||
| C-018 | 权限拦截 | 普通用户访问 /admin | 重定向或权限不足 | 普通 | P0 |
|
||
| C-019 | 登出 | POST /admin/logout | Cookie 清除 | 管理员 | P0 |
|
||
|
||
#### 4.3 Service API
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| C-020 | 列表草稿 | GET /api/service/canvas | 可管理的草稿列表 | 服务 | P1 |
|
||
| C-020a | 所有权隔离 | 服务 A 创建的草稿,服务 B 尝试访问 | 403 或 404 | 服务 | P0 |
|
||
| C-021 | 创建草稿 | POST /api/service/canvas | 成功,返回 slug | 服务 | P1 |
|
||
| C-022 | 更新草稿 | PATCH /api/service/canvas/{slug} | 成功 | 服务 | P1 |
|
||
| C-023 | 删除草稿 | DELETE /api/service/canvas/{slug} | 成功 | 服务 | P1 |
|
||
| C-024 | 无 token | 不带 Authorization | 401 | 无 | P1 |
|
||
|
||
---
|
||
|
||
### 模块 5:Prompt 提示词服务 (prompt.ephron.ren)
|
||
|
||
#### 5.1 公开页面
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| P-001 | 首页加载 | 访问 / | 200,显示提示词列表 | 无 | P0 |
|
||
| P-002 | 搜索 | /?q=关键词 | 返回匹配结果 | 无 | P1 |
|
||
| P-003 | 分类筛选 | /?category=写作 | 按分类显示 | 无 | P1 |
|
||
| P-004 | 标签筛选 | /?tag=xxx | 按标签显示 | 无 | P1 |
|
||
| P-005 | 统计信息 | 检查页面 | 显示总数/模板数/分类数 | 无 | P2 |
|
||
| P-006 | 详情页 | 访问 /prompts/{key} | 显示标题/内容/描述/标签 | 无 | P0 |
|
||
| P-006a | Public JSON API | GET /api/prompts/{key} | 返回 JSON 格式提示词(无需登录) | 无 | P0 |
|
||
| P-006b | Public API 列表 | GET /api/prompts?limit=10&offset=0 | 返回分页提示词列表 | 无 | P1 |
|
||
| P-006c | Public API 版本 | GET /api/prompts/{key}?version=2 | 返回指定版本内容 | 无 | P1 |
|
||
| P-006d | API 草稿拦截 | GET /api/prompts/{key}(该 key 为草稿) | 返回 400 或 404 | 无 | P0 |
|
||
| P-007 | 草稿不可见 | 未登录访问草稿 | 404 | 无 | P0 |
|
||
| P-008 | 404 页面 | 访问 /prompts/not-exist | 404 | 无 | P1 |
|
||
|
||
#### 5.2 管理后台 (/admin)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| P-009 | Admin 首页 | 以管理员访问 /admin | 显示所有提示词(含草稿) | 管理员 | P0 |
|
||
| P-010 | 搜索/筛选 | 在 Admin 搜索/按分类/按标签 | 返回匹配结果 | 管理员 | P1 |
|
||
| P-011 | 新建提示词 | /admin/new,填标题/内容/分类/标签/描述,提交 | 创建成功 | 管理员 | P0 |
|
||
| P-012 | 模板标记 | 创建时勾选「是模板」 | is_template 正确保存 | 管理员 | P1 |
|
||
| P-012a | 模板变量 | 创建模板提示词,填写 variables(CSV 格式) | 变量保存成功 | 管理员 | P1 |
|
||
| P-012b | 示例输入/输出 | 填写 example_input 和 example_output | 保存成功,详情页显示 | 管理员 | P2 |
|
||
| P-012c | 推荐模型 | 填写 recommended_model 字段 | 保存成功,详情页显示 | 管理员 | P2 |
|
||
| P-013 | 编辑提示词 | /admin/edit/{key},修改后保存 | 保存成功 | 管理员 | P0 |
|
||
| P-014 | 删除提示词 | POST /admin/delete/{key} | 删除成功 | 管理员 | P0 |
|
||
| P-015 | 切换草稿 | POST /admin/toggle/{key} | 状态切换 | 管理员 | P0 |
|
||
| P-016 | 版本管理 | 访问 /admin/versions/{key} | 显示版本历史 | 管理员 | P1 |
|
||
| P-017 | 切换版本 | POST /admin/set-version/{key} | 切换到指定版本 | 管理员 | P1 |
|
||
| P-017a | 版本切换后 API | 切换版本后 GET /api/prompts/{key} | 返回新切换的版本内容 | 管理员 | P1 |
|
||
| P-018 | CSRF 保护 | 不带 csrf_token 提交 | 验证失败 | 管理员 | P0 |
|
||
| P-019 | 创建限流 | 1 分钟内 11+ 个 | 第 11 个 429 | 管理员 | P1 |
|
||
| P-020 | 保存限流 | 1 分钟内 21+ 次 | 第 21 次 429 | 管理员 | P1 |
|
||
| P-021 | 权限拦截 | 普通用户访问 /admin | 重定向或权限不足 | 普通 | P0 |
|
||
| P-022 | 登出 | GET /logout | Cookie 清除 | 任意 | P0 |
|
||
|
||
#### 5.3 Service API
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| P-023 | 列表草稿 | GET /api/service/prompts | 可管理的草稿列表 | 服务 | P1 |
|
||
| P-023a | 所有权隔离 | 服务 A 创建的草稿,服务 B 尝试访问 | 403 或 404 | 服务 | P0 |
|
||
| P-024 | 创建草稿 | POST /api/service/prompts | 成功 | 服务 | P1 |
|
||
| P-025 | 更新草稿 | PATCH /api/service/prompts/{key} | 成功 | 服务 | P1 |
|
||
| P-026 | 删除草稿 | DELETE /api/service/prompts/{key} | 成功 | 服务 | P1 |
|
||
| P-027 | 无 token | 不带 Authorization | 401 | 无 | P1 |
|
||
|
||
---
|
||
|
||
### 模块 6:安全与一致性
|
||
|
||
#### 6.1 安全头
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| S-001 | X-Content-Type-Options | 检查响应头 | `nosniff` | P1 |
|
||
| S-002 | X-Frame-Options | 检查响应头 | `DENY` | P1 |
|
||
| S-003 | Referrer-Policy | 检查响应头 | `strict-origin-when-cross-origin` | P1 |
|
||
| S-004 | CSP | 检查 Content-Security-Policy | 存在且合理 | P1 |
|
||
| S-004a | CSP script-src | 检查 script-src 策略 | 仅 `self` + `unsafe-inline`,无 `unsafe-eval` | P1 |
|
||
| S-004b | CSP form-action | 检查 form-action | 仅 `self` | P1 |
|
||
| S-004c | CSP frame-ancestors | 检查 frame-ancestors | `none`(防 clickjacking) | P1 |
|
||
|
||
#### 6.2 一致性检查
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| S-005 | mobile.css 引入 | 检查各页面 HTML | 所有页面一致引入或不引入 | P1 |
|
||
| S-006 | loader.js 引入 | 检查各页面 HTML | 所有页面一致引入 | P1 |
|
||
| S-007 | DOCTYPE 前无多余内容 | 检查各页面源码第一字节 | 无 BOM/换行 | P1 |
|
||
| S-008 | Auth 页导航 | 访问 Auth 登录/注册页 | 有返回主页的链接 | P1 |
|
||
| S-009 | user-scalable | 检查 viewport meta | 无 `user-scalable=no` | P1 |
|
||
| S-009a | AJAX CSRF | Blog/Canvas/Prompt 图片上传和评论审核 | X-CSRF-Token header 验证通过 | P0 |
|
||
| S-009b | Cache-Control | 敏感页面(auth verify/service accounts) | `no-store` 或 `no-cache` | P1 |
|
||
|
||
#### 6.3 控制台检查
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| S-010 | Home 无 JS 错误 | 访问首页,检查控制台 | 无 error | P1 |
|
||
| S-011 | Auth 无 JS 错误 | 访问登录/注册页 | 无 error | P1 |
|
||
| S-012 | Blog 无 JS 错误 | 访问首页/文章详情/Admin | 无 error | P1 |
|
||
| S-013 | Canvas 无 JS 错误 | 访问首页/预览页/Admin | 无 error | P1 |
|
||
| S-014 | Prompt 无 JS 错误 | 访问首页/详情页/Admin | 无 error | P1 |
|
||
|
||
---
|
||
|
||
### 模块 7:边界与异常输入
|
||
|
||
#### 7.1 XSS 注入测试
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| XSS-001 | 文章标题 XSS | Blog Admin 新建文章,标题 `<script>alert('XSS')</script>`,发布后访问 | 渲染为纯文本,不执行脚本 | 管理员 | P0 |
|
||
| XSS-002 | 文章内容 XSS | 内容输入 `<img src=x onerror=alert(1)>` | 不执行,显示 broken image | 管理员 | P0 |
|
||
| XSS-003 | 评论 XSS | 提交评论 `<svg onload=alert(1)>` | 渲染为纯文本,不执行 | 任意 | P0 |
|
||
| XSS-004 | Canvas 标题 XSS | Canvas 标题输入 `<script>alert(1)</script>` | 不执行 | 管理员 | P0 |
|
||
| XSS-005 | Prompt 标题 XSS | Prompt 标题输入 `"><script>alert(1)</script>` | 不执行 | 管理员 | P0 |
|
||
| XSS-006 | 用户名 XSS | 注册时用户名 `<script>alert(1)</script>` | 验证拦截或转义 | 无 | P0 |
|
||
| XSS-007 | 搜索框 XSS | 搜索框 `<script>alert(1)</script>` | 不执行,搜索结果安全显示 | 无 | P0 |
|
||
| XSS-008 | Bio/个人简介 XSS | Admin 修改简介输入 XSS payload | 不执行 | 管理员 | P0 |
|
||
| XSS-009 | 标签 XSS | 添加标签 `<script>alert(1)</script>` | 转义存储,安全显示 | 管理员 | P0 |
|
||
| XSS-010 | URL 参数 XSS | 访问 `?name=<script>alert(1)</script>` | 不执行 | 无 | P1 |
|
||
|
||
#### 7.2 超长字符串输入
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| XSS-011 | 超长文章标题 | 标题输入 10000 字符 | 验证最大长度限制,或截断保存 | 管理员 | P1 |
|
||
| XSS-012 | 超长文章内容 | 内容输入 10MB 文本 | 返回错误或限制(1MB) | 管理员 | P0 |
|
||
| XSS-013 | 超长用户名 | 注册时用户名输入 500 字符 | 验证最大长度限制 | 无 | P1 |
|
||
| XSS-014 | 超长评论 | 评论输入 50000 字符 | 验证长度限制 | 任意 | P1 |
|
||
| XSS-015 | 超长搜索查询 | 搜索框输入 5000 字符 | 验证长度限制或正常处理 | 无 | P1 |
|
||
| XSS-016 | 超长 Canvas 内容 | Canvas 内容输入 50MB | 验证大小限制 | 管理员 | P0 |
|
||
| XSS-017 | 超长 Prompt 内容 | Prompt 内容输入 100000 字符 | 保存成功(无硬性限制则可) | 管理员 | P1 |
|
||
| XSS-018 | 超长邮箱 | 邮箱字段输入 1000 字符 | 验证格式拦截 | 无 | P1 |
|
||
|
||
#### 7.3 特殊字符输入
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| XSS-019 | 特殊字符用户名 | 注册 `user|name` `user&name` `user'name` `user"name` | 验证字符白名单拦截 | 无 | P1 |
|
||
| XSS-020 | 特殊字符标题 | 文章标题含 `/\:*?"<>|` | 验证安全处理 | 管理员 | P1 |
|
||
| XSS-021 | Emoji 标题 | 标题输入 `🎉🔥💻🚀` 等多 emoji | 正常保存和显示 | 管理员 | P1 |
|
||
| XSS-022 | CJK 字符 | 标题/内容输入中日韩字符 `日本語한국어中文` | 正常保存和显示 | 管理员 | P1 |
|
||
| XSS-023 | Unicode 特殊符 | 标题含零宽字符 `` 或双向字符 | 安全处理,不破坏布局 | 管理员 | P1 |
|
||
| XSS-024 | 特殊字符搜索 | 搜索 `AND 1=1--` `OR 1=1` | 安全处理,不报错 | 无 | P1 |
|
||
| XSS-025 | SQL 注入形搜索 | 搜索 `' OR '1'='1` `'; DROP TABLE--` | 安全处理,无 SQL 错误 | 无 | P1 |
|
||
| XSS-026 | 换行符注入 | 标题含 `\n\r` 换行 | 安全保存,显示正常 | 管理员 | P1 |
|
||
|
||
#### 7.4 空内容与边界提交
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| XSS-027 | 空标题文章 | 新建文章,标题留空 | 验证拦截「标题不能为空」 | 管理员 | P0 |
|
||
| XSS-028 | 空内容文章 | 内容留空,填写标题 | 保存为草稿或提示内容不能为空 | 管理员 | P0 |
|
||
| XSS-029 | 空评论提交 | 评论框留空提交 | 验证拦截 | 任意 | P0 |
|
||
| XSS-030 | 仅空白字符 | 标题/内容仅输入空格/制表符 | 视为空内容,拦截 | 管理员 | P1 |
|
||
| XSS-031 | 全角空格 | 标题输入全角空格 ` ` | 视为有效内容或提示输入无效 | 管理员 | P1 |
|
||
| XSS-032 | 仅数字标题 | 标题输入 `123456` | 正常保存 | 管理员 | P1 |
|
||
| XSS-033 | 重复标题 | 创建两篇相同标题文章 | 允许或提示 slug 重复处理 | 管理员 | P1 |
|
||
|
||
---
|
||
|
||
### 模块 8:安全性深度测试
|
||
|
||
#### 8.1 Cookie 属性验证
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEC-001 | auth cookie HttpOnly | curl 检查 `Set-Cookie: ephron_auth` | `HttpOnly` 标记存在 | P0 |
|
||
| SEC-002 | auth cookie Secure | curl (HTTP) 检查 | 生产环境应返回 Secure(需 HTTPS) | P0 |
|
||
| SEC-003 | auth cookie SameSite | 检查 SameSite 属性 | `Lax` 或 `Strict`,不为空 | P0 |
|
||
| SEC-004 | auth cookie Max-Age | 检查 Max-Age 或 Expires | 有合理过期时间(≤30天) | P1 |
|
||
| SEC-005 | auth cookie Domain | 检查 Domain 域 | `.ephron.ren` 以便跨子域共享 | P0 |
|
||
| SEC-006 | CSRF cookie HttpOnly | 检查 ephron_csrf cookie | `HttpOnly=false`(JS 需读取,双提交) | P1 |
|
||
| SEC-007 | Cookie 刷新 | 登录后等 5 分钟再次访问 | Session 保持,cookie 未过期 | 任意 | P1 |
|
||
| SEC-008 | 跨域 Cookie 写入 | 从 blog.ephron.ren 访问 auth.ephron.ren | auth cookie 不被 JS 读取 | P1 |
|
||
|
||
#### 8.2 Open Redirect 深度测试
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEC-009 | redirect 到外域 | `auth.ephron.ren/login?redirect=https://evil.com` | 拒绝或重定向到安全页 | P0 |
|
||
| SEC-010 | redirect 协议相对 | `auth.ephron.ren/login?redirect=//evil.com` | 拒绝,视为相对路径处理或拒绝 | P0 |
|
||
| SEC-011 | redirect 协议注入 | `auth.ephron.ren/login?redirect=javascript:alert(1)` | 拒绝 | P0 |
|
||
| SEC-012 | redirect 路径遍历 | `auth.ephron.ren/login?redirect=/..//evil.com` | 拒绝或规范化处理 | P1 |
|
||
| SEC-013 | redirect 到子域 | `auth.ephron.ren/login?redirect=https://blog.ephron.ren` | 允许(ephron.ren 子域) | P0 |
|
||
| SEC-014 | redirect 空值 | `auth.ephron.ren/login?redirect=` | 使用默认页 | P1 |
|
||
| SEC-015 | redirect URL 编码 | `auth.ephron.ren/login?redirect=%2F%2Fevil.com` | 拒绝或解码后拒绝 | P1 |
|
||
| SEC-016 | 登出后 redirect | 登出时带 redirect 参数 | 拒绝到外部 URL | P1 |
|
||
|
||
#### 8.3 CSRF Token 深度测试
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEC-017 | Token 重放 | 获取 token 后在同一 session 重复使用 | 允许(在有效期内) | P1 |
|
||
| SEC-018 | Token 过期 | 获取 token,等 61 分钟后再使用 | 拒绝,返回 CSRF 验证失败 | P0 |
|
||
| SEC-019 | Token 伪造 | 表单中填入假 token `{timestamp}:fakehex` | 拒绝,HMAC 验证不通过 | P0 |
|
||
| SEC-020 | Token 格式错误 | 表单 token 与 cookie 不一致 | 拒绝 | P0 |
|
||
| SEC-021 | Token 仅 cookie 无表单 | 不在表单中传 token,仅 cookie | 拒绝(双提交需两者匹配) | P0 |
|
||
| SEC-022 | Token 仅表单无 cookie | 传表单 token 但不带 CSRF cookie | 拒绝 | P0 |
|
||
| SEC-023 | Token 不同服务 | 用 blog 的 token 提交到 auth 的表单 | 拒绝(各服务 token 独立) | P1 |
|
||
| SEC-024 | 修改 token 时钟偏倚 | 手动调整请求时间戳到未来/过去 | 过期 token 拒绝 | P1 |
|
||
|
||
#### 8.5 Service Account Token 认证
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEC-033 | Bearer Token 认证 | 用有效 service token 请求 /api/service/* | 200,返回数据 | P0 |
|
||
| SEC-034 | Token SHA256 查找 | 数据库中 token 为 SHA256 哈希 | 明文 token 不存储 | P0 |
|
||
| SEC-035 | Token 使用追踪 | 使用 token 后检查 last_used_at/ip/ua | 记录更新 | P1 |
|
||
| SEC-036 | Token 过期 | 使用带 expires_at 的过期 token | 401 | P0 |
|
||
| SEC-037 | 吊销 Token | 吊销后使用旧 token | 401 | P0 |
|
||
| SEC-038 | Token 跨服务权限 | Blog service token 访问 Canvas API | 403(各服务独立) | P0 |
|
||
|
||
#### 8.4 路径遍历与文件安全
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEC-025 | 文章 slug 路径遍历 | 访问 `/posts/../../../etc/passwd` | 404 或安全拒绝 | P0 |
|
||
| SEC-026 | Canvas slug 路径遍历 | 访问 `/view/../../secret.txt` | 404 | P0 |
|
||
| SEC-027 | Prompt key 路径遍历 | 访问 `/prompts/../../config.py` | 404 | P0 |
|
||
| SEC-028 | 管理接口越权 | 普通用户直接 POST 到 admin 接口 | 403 | 普通 | P0 |
|
||
| SEC-029 | 直接访问管理 API | curl 绕过 UI 访问 `/admin/api/...` | RBAC 拦截 | 普通 | P0 |
|
||
| SEC-030 | 文件上传绕过扩展名 | 上传 `shell.php.jpg` | 应拒绝(只允许图片类型) | 管理员 | P0 |
|
||
| SEC-031 | 文件上传 MIME 类型绕过 | POST 修改 Content-Type 但内容是 HTML | 验证文件内容而非仅 MIME | 管理员 | P1 |
|
||
| SEC-032 | 文件名 XSS | 上传含 `<script>` 文件名的图片 | 存储时清理文件名 | 管理员 | P1 |
|
||
|
||
---
|
||
|
||
### 模块 9:会话管理
|
||
|
||
#### 9.1 Token 生命周期
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SES-001 | Token 过期跳转 | 等待 token 过期后访问受保护页 | 重定向到 login 页 | 任意 | P0 |
|
||
| SES-002 | Token 过期 API | 用过期 token 请求 API | 401 `{"error": "token expired"}` | 任意 | P0 |
|
||
| SES-003 | 角色降级权限刷新 | 管理员登录后 DB 改为 user,刷新页面 | 页面应反映新权限(读取 DB 角色) | 管理员 | P0 |
|
||
| SES-004 | 角色升级权限刷新 | user 登录后 DB 改为 admin,刷新 | 需重新登录才生效(session 不自动刷新) | 普通 | P1 |
|
||
| SES-005 | 用户禁用后会话 | 用户登录后 DB 禁用账号,已存 cookie 访问 | 拒绝访问或立即登出 | 任意 | P0 |
|
||
| SES-006 | 多设备登录 | 同时两台设备用同一账号 | 两 session 均有效,或强制下线 | 任意 | P1 |
|
||
| SES-007 | 登录成功 token 刷新 | 登录后检查是否有新 session 产生 | 每次登录产生新 token | 任意 | P1 |
|
||
|
||
#### 9.2 并发会话安全
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SES-008 | 并发编辑草稿 | 两浏览器同时编辑同一文章并保存 | 后保存覆盖先前,或加锁提示冲突 | 管理员 | P1 |
|
||
| SES-009 | 并发评论 | 多用户同时对同一文章提交评论 | 均成功存储,时间戳不同 | 任意 | P1 |
|
||
| SES-010 | 并发点赞 | 多用户同时对同一文章 toggle 点赞 | 计数正确,无 race condition | 任意 | P1 |
|
||
| SES-011 | Session 固定攻击 | 登录前 cookie 值 A,登录后 cookie 变为 B | 登录后 session ID 必须更换 | 任意 | P0 |
|
||
|
||
---
|
||
|
||
### 模块 10:文件上传安全
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| UPL-001 | 图片上传正常 | 上传 1MB jpg 文件 | 成功,返回 URL | 管理员 | P0 |
|
||
| UPL-002 | PNG 上传 | 上传 2MB png | 成功 | 管理员 | P0 |
|
||
| UPL-003 | WebP 上传 | 上传 webp 格式 | 成功 | 管理员 | P0 |
|
||
| UPL-004 | GIF 上传 | 上传 500KB gif | 成功 | 管理员 | P0 |
|
||
| UPL-005 | 大小限制 | 上传 10MB 文件 | 返回错误「文件超过 5MB」 | 管理员 | P0 |
|
||
| UPL-006 | 双扩展名 | 上传 `shell.php.jpg` | 拒绝(后端验证真实类型) | 管理员 | P0 |
|
||
| UPL-007 | 可执行文件 | 上传 `shell.exe` | 拒绝,仅允许图片类型 | 管理员 | P0 |
|
||
| UPL-008 | 恶意 SVG | 上传含 `<script>alert(1)</script>` 的 SVG | 拒绝或净化处理 | 管理员 | P0 |
|
||
| UPL-009 | polyglot 文件 | 上传既是图片又是 HTML 的文件 | 拒绝,内容检查 | 管理员 | P0 |
|
||
| UPL-010 | 0 字节文件 | 上传 0 字节文件 | 拒绝或提示无效文件 | 管理员 | P1 |
|
||
| UPL-011 | 超大文件名 | 上传文件名 500 字符 | 截断或正常处理 | 管理员 | P1 |
|
||
| UPL-012 | 路径穿越文件名 | 上传 `../../../etc/passwd.jpg` | 规范化文件名,安全存储 | 管理员 | P0 |
|
||
| UPL-013 | 上传覆盖 | 上传与已有文件同名的图片 | UUID 化命名,不覆盖 | 管理员 | P1 |
|
||
| UPL-014 | 未登录上传 | 未登录尝试上传 | 401 重定向到登录 | 无 | P0 |
|
||
| UPL-015 | 普通用户上传 | 普通用户尝试上传 | 403 权限不足 | 普通 | P0 |
|
||
|
||
---
|
||
|
||
### 模块 11:搜索边界测试
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 账号 | 优先级 |
|
||
|------|----------|------|------|------|--------|
|
||
| SCH-001 | 空搜索 | `/?q=` 或 `/?q=%20%20` | 显示所有内容 | 无 | P1 |
|
||
| SCH-002 | 单字符搜索 | `/?q=a` | 有结果或空结果提示 | 无 | P1 |
|
||
| SCH-003 | 超长搜索 | `/?q=` + 10000 字符 | 验证长度限制 | 无 | P1 |
|
||
| SCH-004 | SQL 注入搜索 | `/?q=' OR 1=1--` | 安全处理,显示空结果或报错 | 无 | P0 |
|
||
| SCH-005 | 正则注入 | `/?q=(?<=.*)` 特殊正则元字符 | 安全处理 | 无 | P1 |
|
||
| SCH-006 | 搜索结果 XSS | 搜索含 `<script>` 内容后查看结果高亮 | 转义高亮显示 | 无 | P0 |
|
||
| SCH-007 | 搜索跨服务 | auth 服务搜索 `/?q=blogpost` | 正常处理(auth 无搜索则跳过) | 无 | P1 |
|
||
| SCH-008 | 搜索结果分页 | 搜索结果超过单页 | 分页控件正常 | 无 | P1 |
|
||
| SCH-009 | 搜索历史 | 输入搜索词后刷新页面 | 搜索框保留上次内容 | 无 | P2 |
|
||
|
||
---
|
||
|
||
### 模块 12:SEO 元数据测试
|
||
|
||
#### 12.1 Home 服务
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEO-001 | 首页 title | 访问 www.ephron.ren,查看 `<title>` | 有描述性 title,非默认 | P1 |
|
||
| SEO-002 | 首页 meta description | 检查 `<meta name="description">` | 有且长度合理(150字符左右) | P1 |
|
||
| SEO-003 | 首页 OG 标签 | 检查 `og:title`, `og:description`, `og:image`, `og:url` | 全部存在 | P1 |
|
||
| SEO-004 | 首页 canonical | 检查 `<link rel="canonical">` | 存在,指向自身 | P2 |
|
||
| SEO-005 | 首页 robots | 检查 robots meta 或 headers | `index, follow` | P2 |
|
||
| SEO-006 | 响应式 viewport | 检查 viewport meta | 含 `width=device-width, initial-scale=1` | P1 |
|
||
| SEO-007 | 首页 icon | 检查 favicon.ico / apple-touch-icon | 存在 | P2 |
|
||
|
||
#### 12.2 Blog 服务
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEO-008 | 文章 title | 访问文章详情页 `<title>` | 含文章标题 + 站点名 | P1 |
|
||
| SEO-009 | 文章 meta description | 检查 description 内容 | 文章摘要或前 160 字符 | P1 |
|
||
| SEO-010 | 文章 OG 标签 | 检查 og:title, og:description, og:image | 全部存在 | P1 |
|
||
| SEO-011 | 文章 canonical | 检查 canonical URL | 存在且正确 | P1 |
|
||
| SEO-012 | RSS feed | 访问 /feed | 有效 XML,有 items | P1 |
|
||
| SEO-013 | sitemap.xml | 访问 /sitemap.xml | 有效 XML,包含所有已发布文章 | P1 |
|
||
| SEO-014 | 文章结构化数据 | 检查 JSON-LD | 有 Article 或 BlogPosting schema | P2 |
|
||
| SEO-015 | 归档页 title | 访问 /archive | 有描述性 title | P2 |
|
||
| SEO-016 | 标签页 title | 访问 /tags/{tag} | 含标签名 + 站点名 | P2 |
|
||
|
||
#### 12.3 Canvas 服务
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEO-017 | Canvas 预览页 title | 访问 /view/{slug} | 含标题 + 站点名 | P2 |
|
||
| SEO-018 | Canvas OG image | 检查 og:image | 存在(如有缩略图) | P2 |
|
||
|
||
#### 12.4 Prompt 服务
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEO-019 | Prompt 详情页 title | 访问 /prompts/{key} | 含标题 + 站点名 | P2 |
|
||
| SEO-020 | Prompt 详情页 description | 检查 meta description | 存在 | P2 |
|
||
|
||
#### 12.5 robots.txt
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| SEO-021 | robots.txt 存在 | 各子服务访问 /robots.txt | 存在内容 | P1 |
|
||
| SEO-022 | robots.txt 有效性 | 检查 sitemap 指令 | 指向正确的 sitemap URL | P1 |
|
||
|
||
---
|
||
|
||
### 模块 13:无障碍(Accessibility)深度测试
|
||
|
||
#### 13.1 键盘导航
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| A11Y-001 | 焦点可见性 | Tab 键遍历首页 | 每个焦点元素有可见轮廓 | P1 |
|
||
| A11Y-002 | 表单键盘操作 | 在登录表单中 Tab 切换字段,Enter 提交 | 顺序正确,Enter 提交 | 无 | P1 |
|
||
| A11Y-003 | 模态框键盘 | 打开联系弹窗后 Tab | 焦点锁定在弹窗内 | 无 | P1 |
|
||
| A11Y-004 | 下拉菜单键盘 | 使用键盘操作下拉菜单 | 上下箭头选择,Enter 确认 | 无 | P1 |
|
||
| A11Y-005 | 跳过导航 | 按 Tab 后首个链接 | 应为「跳过到主要内容」链接 | P1 |
|
||
| A11Y-006 | 编辑器键盘操作 | Blog Admin 编辑器,键盘操作 | 可用键盘完成基本编辑 | 管理员 | P1 |
|
||
|
||
#### 13.2 ARIA 与语义化
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| A11Y-007 | 图片 alt | 所有 `<img>` 有 alt 属性 | 装饰性图片有 `alt=""` 或 `aria-hidden` | P1 |
|
||
| A11Y-008 | 按钮语义 | 使用 `<button>` 而非 `<div onclick>` | 正确语义标签 | P1 |
|
||
| A11Y-009 | 表单 label | 登录表单每个 input 有 `<label>` | label 与 input 关联 | P1 |
|
||
| A11Y-010 | ARIA label | 图标按钮有 `aria-label` | 含义明确 | P1 |
|
||
| A11Y-011 | 导航 landmark | `<nav>` 标签存在 | 导航区有正确语义 | P2 |
|
||
| A11Y-012 | 标题层级 | H1/H2/H3 层级不跳过 | 逻辑清晰 | P1 |
|
||
|
||
#### 13.3 颜色对比度
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| A11Y-013 | 正文对比度 | 白色背景上正文文字 | 至少 4.5:1(AA 标准) | P1 |
|
||
| A11Y-014 | 大文字对比度 | 标题文字与背景 | 至少 3:1 | P1 |
|
||
| A11Y-015 | 链接颜色 | 正文链接颜色与正文 | 4.5:1 或有下划线 | P1 |
|
||
| A11Y-016 | 错误提示颜色 | 红色错误文字 | 不仅依赖颜色传达信息 | P1 |
|
||
| A11Y-017 | 按钮 hover | 按钮 hover 状态有视觉变化 | 非仅颜色变化(加下划线/边框) | P1 |
|
||
|
||
---
|
||
|
||
### 模块 14:性能测试
|
||
|
||
#### 14.1 页面加载
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| PERF-001 | 首页加载时间 | 访问首页,测量 TTFB | < 1s | P1 |
|
||
| PERF-002 | 首页完全加载 | 测量 onload 时间 | < 3s | P1 |
|
||
| PERF-003 | 文章详情加载 | 访问含代码块/LaTeX 的文章 | < 3s | P1 |
|
||
| PERF-004 | 静态资源 200 | 所有 CSS/JS/图片 | 全部 HTTP 200,无 404 | P0 |
|
||
| PERF-005 | 外部资源 | 检查 Google Fonts / CDN 资源 | 可访问(中国大陆考虑 jsDelivr 备选) | P1 |
|
||
| PERF-006 | 资源重复请求 | 检查同一资源是否多次请求 | 无重复请求相同资源 | P2 |
|
||
| PERF-007 | 图片懒加载 | 博客列表页图片 | 进入视口前不加载 | P2 |
|
||
|
||
#### 14.2 Core Web Vitals(简化测试)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| PERF-008 | LCP 预估 | 首页加载后最大图片/文字渲染 | < 2.5s | P2 |
|
||
| PERF-009 | CLS 检测 | 页面加载后无布局偏移 | 无意外布局移动 | P2 |
|
||
| PERF-010 | 无长任务 | 浏览器 Performance 标签 | 无 > 50ms 的主线程阻塞 | P2 |
|
||
|
||
#### 14.3 首屏渲染
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| PERF-011 | 首屏无白屏 | 访问首页 | 1s 内显示内容 | P1 |
|
||
| PERF-012 | 首屏骨架屏 | 慢网速模拟 | 有 loading 状态 | P2 |
|
||
| PERF-013 | 内联 CSS | 检查 `<head>` 内联 CSS | 首屏内容立即可用 | P2 |
|
||
|
||
---
|
||
|
||
### 模块 15:移动端交互测试
|
||
|
||
#### 15.1 响应式布局
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| MOBILE-001 | 375px 布局 | Chrome DevTools 设为 iPhone 12 宽度 | 无水平滚动,布局正常 | P1 |
|
||
| MOBILE-002 | 768px 布局 | 设为 iPad 宽度 | 布局自适应 | P1 |
|
||
| MOBILE-003 | 导航响应 | 375px 下导航栏 | 汉堡菜单或适配移动端 | P1 |
|
||
| MOBILE-004 | 点击区域大小 | 按钮/链接触摸目标 | ≥ 44x44px | P1 |
|
||
| MOBILE-005 | 内容溢出 | 长标题/长单词在移动端 | 自动换行,不溢出 | P1 |
|
||
|
||
#### 15.2 触摸交互
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| MOBILE-006 | 触摸滚动 | 触摸博客列表页 | 平滑滚动 | 无 | P1 |
|
||
| MOBILE-007 | 点击反馈 | 触摸按钮 | 有视觉反馈(ripple/高亮) | P1 |
|
||
| MOBILE-008 | 双击缩放 | 触摸文字 | 无意外缩放(已设 viewport) | P1 |
|
||
| MOBILE-009 | 虚拟键盘 | 移动端点击评论输入框 | 键盘弹出,页面适当上推 | 任意 | P1 |
|
||
| MOBILE-010 | 横竖屏切换 | 旋转设备方向 | 布局正常重排 | P2 |
|
||
|
||
---
|
||
|
||
### 模块 16:跨浏览器兼容性(简化测试)
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| COMP-001 | Flexbox 兼容性 | 检查 CSS 是否使用有前缀的 Flexbox | 无仅 Webkit 前缀的旧语法 | P1 |
|
||
| COMP-002 | CSS Grid 兼容性 | 检查是否用了不支持的 Grid 语法 | 提供回退方案 | P2 |
|
||
| COMP-003 | HTTP/2 支持 | 检查服务器 HTTP/2 | 服务器支持 HTTP/2 | P2 |
|
||
| COMP-004 | CORS headers | 静态资源跨域请求 | 正确 CORS 头 | P2 |
|
||
| COMP-005 | ES6+ 语法 | 检查 JS 是否用了现代语法 | 无仅旧浏览器支持的语法 | P1 |
|
||
|
||
---
|
||
|
||
### 模块 17:运维与部署相关
|
||
|
||
#### 17.1 健康检查
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| OPS-001 | Home 健康检查 | `curl https://www.ephron.ren/health` | `{"status":"ok"}` | P1 |
|
||
| OPS-002 | Auth 健康检查 | `curl https://auth.ephron.ren/health` | `{"status":"ok"}` | P1 |
|
||
| OPS-003 | Blog 健康检查 | `curl https://blog.ephron.ren/health` | `{"status":"ok"}` | P1 |
|
||
| OPS-004 | Canvas 健康检查 | `curl https://canvas.ephron.ren/health` | `{"status":"ok"}` | P1 |
|
||
| OPS-005 | Prompt 健康检查 | `curl https://prompt.ephron.ren/health` | `{"status":"ok"}` | P1 |
|
||
| OPS-006 | 健康检查无认证 | 无 cookie 访问健康检查 | 正常返回(不应需要认证) | P1 |
|
||
|
||
#### 17.2 错误处理
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| OPS-007 | 自定义 404 | 访问 `/not-exist-page-xxx` | 显示自定义 404 页面,不泄露信息 | P1 |
|
||
| OPS-008 | 自定义 500 | 触发服务器错误(如有 debug 接口) | 不暴露 stack trace | P1 |
|
||
| OPS-009 | 错误页面一致性 | 各子服务 404 页面 | 风格统一 | P2 |
|
||
| OPS-010 | API 404 | GET 不存在的 API 路由 | 返回 JSON `{"detail": "Not Found"}` | P1 |
|
||
| OPS-011 | 方法不允许 | POST 到只允许 GET 的页面 | 405 Method Not Allowed | P1 |
|
||
|
||
#### 17.3 日志与审计
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| OPS-012 | 登录日志 | 用错误密码登录 3 次,成功 1 次 | 查看审计日志有记录 | 管理员 | P1 |
|
||
| OPS-013 | 管理操作日志 | Admin 执行禁用用户操作 | 审计日志有记录,含 actor/time/action | 管理员 | P1 |
|
||
| OPS-014 | 日志不含敏感 | 检查日志中是否有明文密码/token | 不应明文记录敏感信息 | P0 |
|
||
| OPS-015 | 登出日志 | 登出后检查审计日志 | 有登出记录 | 任意 | P2 |
|
||
|
||
#### 17.4 数据库迁移
|
||
|
||
| 编号 | 测试内容 | 步骤 | 预期 | 优先级 |
|
||
|------|----------|------|------|--------|
|
||
| OPS-016 | 迁移脚本存在 | 检查 `alembic/` 或 `migrations/` | 有版本化迁移脚本 | P1 |
|
||
| OPS-017 | 迁移幂等性 | 运行同一迁移两次 | 第二次应是无操作(幂等) | P1 |
|
||
| OPS-018 | 回滚脚本存在 | 检查是否有 downgrade 迁移 | 可回滚到上一版本 | P2 |
|
||
|
||
---
|
||
|
||
## 三、测试执行流程
|
||
|
||
```
|
||
Step 1 → Auth 登录(获取 Cookie)
|
||
Step 2 → Home:公开页面 + /admin 全流程(结构化 JSON + Service Token 拒绝)
|
||
Step 3 → Auth:注册全流程(密码复杂度/用户名黑名单/邮箱唯一性/邀请码过期/限流)
|
||
Step 4 → Auth:/admin 全部子页面(用户/邀请码/角色/审计/服务账号)
|
||
Step 5 → Blog:公开页面 + 搜索(simple + fulltext + 中文分词)+ 评论 + 点赞
|
||
Step 6 → Blog:/admin + 评论管理 + 图片上传(WebP 转换)+ 置顶排序
|
||
Step 7 → Blog:Service API 所有权隔离测试
|
||
Step 8 → Canvas:公开页面 + /admin + slug 验证 + Service API
|
||
Step 9 → Prompt:公开页面 + Public JSON API + /admin + 版本管理 + Service API
|
||
Step 10 → 权限测试:普通用户访问所有 /admin + API min_role 验证
|
||
Step 11 → 安全测试:CSRF/AJAX CSRF/限流/安全头/CSP 细节/缓存头
|
||
Step 12 → 控制台检查:每个页面的 JS 错误
|
||
Step 13 → 边界输入:XSS/超长/特殊字符/空提交
|
||
Step 14 → 安全深度:Cookie 属性/Open Redirect/CSRF 重放/Service Token 认证
|
||
Step 15 → 会话管理:Token 过期/角色变更/并发
|
||
Step 16 → 文件上传安全:恶意文件/双扩展/SVG
|
||
Step 17 → 搜索边界:注入/超长/特殊字符
|
||
Step 18 → SEO:OG 标签/canonical/RSS/sitemap
|
||
Step 19 → 无障碍:键盘导航/ARIA/颜色对比度
|
||
Step 20 → 性能:加载时间/Core Web Vitals/首屏
|
||
Step 21 → 移动端:响应式/触摸/虚拟键盘
|
||
Step 22 → 运维:健康检查/错误处理/日志/迁移
|
||
Step 23 → 源码分析:定位问题根因
|
||
Step 24 → 生成 Excel 报告
|
||
```
|
||
|
||
---
|
||
|
||
## 四、执行说明
|
||
|
||
### 执行策略
|
||
|
||
| 阶段 | 覆盖模块 | 优先级 | 预计时间 |
|
||
|------|----------|--------|----------|
|
||
| P0 优先 | 模块 1-6 全部 P0 + 模块 7-17 P0 用例 | ~120 用例 | 2-3 小时 |
|
||
| P1 全面 | 全部 P1 用例 | ~150 用例 | 2-3 小时 |
|
||
| P2 完善 | 全部 P2 用例 | ~96 用例 | 1-2 小时 |
|
||
|
||
### 环境要求
|
||
|
||
- 测试环境:生产环境(https://www.ephron.ren/)
|
||
- 浏览器:Chrome(DevTools for mobile/network/console)
|
||
- 网络:能够访问所有 5 个子服务
|
||
- 测试账号:见 1.2 节
|
||
|
||
### 工具建议
|
||
|
||
- 浏览器 DevTools(Console/Network/Performance)
|
||
- curl(HTTP 测试、安全头检查)
|
||
- Chrome Lighthouse(SEO + Performance)
|
||
- axe-core 或 Accessibility Insights(无障碍)
|
||
- Burp Suite 或 Postman(安全测试)
|
||
|
||
---
|
||
|
||
## 五、统计总表
|
||
|
||
| 模块 | 测试用例数 |
|
||
|------|:----------:|
|
||
| 模块 1:Home | 24 |
|
||
| 模块 2:Auth | 85 |
|
||
| 模块 3:Blog | 69 |
|
||
| 模块 4:Canvas | 29 |
|
||
| 模块 5:Prompt | 36 |
|
||
| 模块 6:安全与一致性 | 19 |
|
||
| 模块 7:边界与异常输入 | 33 |
|
||
| 模块 8:安全性深度测试 | 38 |
|
||
| 模块 9:会话管理 | 11 |
|
||
| 模块 10:文件上传安全 | 15 |
|
||
| 模块 11:搜索边界测试 | 9 |
|
||
| 模块 12:SEO 元数据测试 | 22 |
|
||
| 模块 13:无障碍深度测试 | 17 |
|
||
| 模块 14:性能测试 | 13 |
|
||
| 模块 15:移动端交互测试 | 10 |
|
||
| 模块 16:跨浏览器兼容性 | 5 |
|
||
| 模块 17:运维与部署相关 | 18 |
|
||
| **全量合计** | **453** |
|
||
|
||
---
|
||
|
||
*文档版本: v4.0 | 最后更新: 2026-05-03*
|