Some checks failed
Security / deep-security-scan (push) Failing after 20m5s
DR Drill / dr-drill (push) Failing after 1m31s
CI / scheduled-backup (push) Failing after 1m31s
CI / backup-verify (push) Has been skipped
CI / weekly-dr-drill (push) Failing after 0s
CI / build-deploy (push) Has been cancelled
CI / security-scan (push) Has been cancelled
主要变更: - 新增 lesson-preparation 模块: 备课编辑器、节点编辑、AI 建议、知识点选择、版本历史、作业发布 - 新增 shared 通用组件: charts/question-bank-filters/schedule-list/ui (chip-nav/filter-bar/page-header/stat-card/stat-item) - 新增 student/admin 端 loading.tsx 与 error.tsx, 优化加载与错误态体验 - 新增 teacher/lesson-plans 页面 (列表/新建/编辑) - 新增 drizzle 迁移 0002_tiny_lionheart 及 snapshot - 新增 textbooks/schema.ts 与 exams/utils/normalize-structure.ts - 修复 Tiptap v3 SSR hydration 崩溃 (rich-text-block immediatelyRender: false) - 重构多模块 data-access/actions/组件, 修复权限校验与类型规范 - 同步架构文档 004/005 反映新增模块、导出、依赖关系 - 归档 bugs/* 测试报告与 e2e 测试脚本 (admin/parent/student/teacher web_test)
278 lines
12 KiB
Markdown
278 lines
12 KiB
Markdown
# 家长端 Web 功能测试报告
|
||
|
||
> 测试日期:2026-06-20 12:28:43
|
||
> 测试范围:家长端所有页面功能 + 跨角色权限隔离
|
||
> 测试工具:Playwright + Chromium (headless)
|
||
> 测试账号:parent_g1c1_1@xiaoxue.edu.cn
|
||
> Base URL:http://localhost:3000
|
||
|
||
---
|
||
|
||
## 一、测试概览
|
||
|
||
| 指标 | 数值 |
|
||
|------|------|
|
||
| 总测试页面数 | 24 |
|
||
| 通过 | 17 |
|
||
| 失败 | 7 |
|
||
| 警告 | 0 |
|
||
| 页面通过率 | 70.8% |
|
||
| 功能检查通过率 | 24/24 (100.0%) |
|
||
| 安全检查通过率 | 1/1 (100.0%) |
|
||
|
||
---
|
||
|
||
## 二、关键发现
|
||
|
||
### ⚠️ 严重:跨角色访问控制失效(安全漏洞)
|
||
|
||
家长账号可以访问教师端页面,权限隔离失效。根因分析:
|
||
|
||
- [`src/proxy.ts`](../src/proxy.ts#L10-L16) 中 `/teacher` 路由前缀仅要求 `EXAM_READ` 权限
|
||
- [`src/shared/lib/permissions.ts`](../src/shared/lib/permissions.ts#L125-L136) 中家长角色被授予了 `EXAM_READ` 权限
|
||
- 因此家长通过了 proxy 的权限检查,可以访问所有 `/teacher/*` 页面
|
||
|
||
受影响页面:
|
||
|
||
| 路由 | HTTP | 表现 |
|
||
|------|------|------|
|
||
| `/teacher/dashboard` | 500 | HTTP 500(页面崩溃) |
|
||
| `/teacher/exams` | 200 | 成功访问并重定向到 `/teacher/exams/all` |
|
||
| `/teacher/homework` | 500 | HTTP 500(页面崩溃) |
|
||
| `/teacher/grades` | 200 | 成功访问(HTTP 200) |
|
||
| `/teacher/questions` | 200 | 成功访问(HTTP 200) |
|
||
| `/teacher/classes` | 200 | 成功访问并重定向到 `/teacher/classes/my` |
|
||
| `/teacher/attendance` | 200 | 成功访问(HTTP 200) |
|
||
|
||
**修复建议**:
|
||
|
||
1. 在 `src/proxy.ts` 中为 `/teacher` 路由前缀增加角色校验(要求 `teacher` / `grade_head` / `teaching_head` 角色),或
|
||
2. 在 `src/shared/lib/permissions.ts` 中移除家长角色的 `EXAM_READ` 权限(如果家长不需要查看考试),或
|
||
3. 在各教师端页面的 Server Component 中增加 `requireRole()` 角色校验,作为深度防御
|
||
|
||
### ✅ 家长端核心功能正常
|
||
|
||
- 家长端 10 个页面全部正常加载(HTTP 200)
|
||
- 功能完整性检查 24/24 项通过
|
||
- 跨家庭信息隔离正常工作(访问非关联子女返回 Access denied)
|
||
- 侧边栏导航正确显示家长菜单,未泄露教师/管理员菜单
|
||
- 子女详情页邮箱掩码、作业摘要、成绩趋势、今日课表等功能完整
|
||
|
||
---
|
||
|
||
## 三、页面测试详情
|
||
|
||
### Announcements
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/announcements` | 200 | passed | - |
|
||
|
||
### Attendance
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/parent/attendance` | 200 | passed | - |
|
||
|
||
### Child Detail
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/parent/children/user_s_g1c1_1` | 200 | passed | 警告: Error text on page: Due 2026年6月18日 |
|
||
|
||
### Cross-Role Access Control
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/admin/dashboard` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fadmin%2Fdashboard&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
| ✅ | `/admin/school` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fadmin%2Fschool&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
| ❌ | `/teacher/dashboard` | 500 | failed | 错误: 跨角色访问返回 HTTP 500(应被重定向拦截)<br>错误: Failed to load resource: the server responded with a status of 500 (Internal Server Error) |
|
||
| ❌ | `/teacher/exams` | 200 | failed | 重定向: `/teacher/exams/all`<br>错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/exams/all),权限隔离失效<br>错误: %o |
|
||
| ❌ | `/teacher/homework` | 500 | failed | 重定向: `/teacher/homework/assignments`<br>错误: 跨角色访问返回 HTTP 500(应被重定向拦截)<br>错误: Failed to load resource: the server responded with a status of 500 (Internal Server Error) |
|
||
| ❌ | `/teacher/grades` | 200 | failed | 错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/grades),权限隔离失效 |
|
||
| ❌ | `/teacher/questions` | 200 | failed | 错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/questions),权限隔离失效 |
|
||
| ❌ | `/teacher/classes` | 200 | failed | 重定向: `/teacher/classes/my`<br>错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/classes/my),权限隔离失效 |
|
||
| ❌ | `/teacher/attendance` | 200 | failed | 错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/attendance),权限隔离失效 |
|
||
| ✅ | `/student/dashboard` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fdashboard&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
| ✅ | `/student/learning` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Flearning&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
| ✅ | `/student/grades` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fgrades&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
| ✅ | `/student/attendance` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
| ✅ | `/management/grade/classes` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fmanagement%2Fgrade%2Fclasses&reason=forbidden`<br>跨角色访问被权限系统拦截 |
|
||
|
||
### Dashboard
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/parent/dashboard` | 200 | passed | - |
|
||
|
||
### Grades
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/parent/grades` | 200 | passed | - |
|
||
|
||
### Messages
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/messages` | 200 | passed | - |
|
||
| ✅ | `/messages/compose` | 200 | passed | - |
|
||
|
||
### Profile
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/profile` | 200 | passed | - |
|
||
|
||
### Settings
|
||
|
||
| 状态 | 路由 | HTTP | 结果 | 备注 |
|
||
|------|------|------|------|------|
|
||
| ✅ | `/settings` | 200 | passed | - |
|
||
| ✅ | `/settings/security` | 200 | passed | - |
|
||
|
||
---
|
||
|
||
## 四、功能完整性检查
|
||
|
||
| 状态 | 检查项 | 期望 | 实际 |
|
||
|------|--------|------|------|
|
||
| ✅ | 返回仪表盘按钮 | 存在 Back to Dashboard 链接 | Found |
|
||
| ✅ | 子女姓名标题 | 显示子女姓名 | 小明 |
|
||
| ✅ | 邮箱掩码处理 | 邮箱被掩码为 j***@domain.com | Masked |
|
||
| ✅ | 作业摘要卡片 | 显示 {childName}'s Homework | Found |
|
||
| ✅ | 作业统计 - Pending | 显示 Pending 计数 | Found |
|
||
| ✅ | 作业统计 - Submitted | 显示 Submitted 计数 | Found |
|
||
| ✅ | 作业统计 - Graded | 显示 Graded 计数 | Found |
|
||
| ✅ | 成绩趋势卡片 | 显示成绩信息 | Found |
|
||
| ✅ | 今日课表卡片 | 显示 {childName}'s Today Schedule | Found |
|
||
| ✅ | View all 链接 | 存在 View all 链接 | Found |
|
||
| ✅ | 仪表盘标题 | Parent Dashboard | Parent Dashboard |
|
||
| ✅ | 问候语显示 | Good morning/afternoon/evening 或 Welcome | Found |
|
||
| ✅ | Grades 快捷入口 | 存在 | Found |
|
||
| ✅ | Attendance 快捷入口 | 存在 | Found |
|
||
| ✅ | Announcements 快捷入口 | 存在 | Found |
|
||
| ✅ | 子女卡片显示 | ≥1 个子女卡片 | 1 个 |
|
||
| ✅ | 子女卡片 - Pending 统计 | 显示 Pending 计数 | Found |
|
||
| ✅ | 子女卡片 - Overdue 统计 | 显示 Overdue 计数 | Found |
|
||
| ✅ | 子女数量提示 | 显示 'N child(ren) linked' | Found |
|
||
| ✅ | 侧边栏 - Dashboard | 显示 Dashboard 导航项 | Found |
|
||
| ✅ | 侧边栏 - Grades | 显示 Grades 导航项 | Found |
|
||
| ✅ | 侧边栏 - Attendance | 显示 Attendance 导航项 | Found |
|
||
| ✅ | 侧边栏 - Announcements | 显示 Announcements 导航项 | Found |
|
||
| ✅ | 侧边栏 - Messages | 显示 Messages 导航项 | Found |
|
||
|
||
---
|
||
|
||
## 五、安全检查
|
||
|
||
| 状态 | 检查项 | 期望 | 实际 |
|
||
|------|--------|------|------|
|
||
| ✅ | 访问不存在/非关联子女应被拒绝 | 显示 Access denied 或 404 | Access denied |
|
||
|
||
---
|
||
|
||
## 六、失败页面详情
|
||
|
||
### ❌ `/teacher/dashboard`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 500
|
||
- **错误信息**:
|
||
- 跨角色访问返回 HTTP 500(应被重定向拦截)
|
||
- Failed to load resource: the server responded with a status of 500 (Internal Server Error)
|
||
- %o
|
||
|
||
%s Error: Teacher not found
|
||
at getTeacherIdForMutations (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__458f1717._.js?61:9381:27)
|
||
at TeacherDashboardPage (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks...(已截断)
|
||
|
||
### ❌ `/teacher/exams`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 200
|
||
- **重定向**: `http://localhost:3000/teacher/exams/all`
|
||
- **错误信息**:
|
||
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/exams/all),权限隔离失效
|
||
- %o
|
||
|
||
%s Error: Failed query: select `exams`.`id`, `exams`.`title`, `exams`.`description`, `exams`.`structure`, `exams`.`creator_id`, `exams`.`subject_id`, `exams`.`grade_id`, `exams`.`start_time`, `exams`.`end_time`, `exams`.`exam_mode`, `exams`.`duration_minutes`, `exams`.`shuffle_questions`, `exams...(已截断)
|
||
|
||
### ❌ `/teacher/homework`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 500
|
||
- **重定向**: `http://localhost:3000/teacher/homework/assignments`
|
||
- **错误信息**:
|
||
- 跨角色访问返回 HTTP 500(应被重定向拦截)
|
||
- Failed to load resource: the server responded with a status of 500 (Internal Server Error)
|
||
- %o
|
||
|
||
%s Error: Teacher not found
|
||
at getTeacherIdForMutations (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Cssr%5C%5Broot-of-the-server%5D__458f1717._.js?47:9381:27)
|
||
at AssignmentsPage (about://React/Server/E:%5CDesktop%5CCICD%5C.next%5Cdev%5Cserver%5Cchunks%5Css...(已截断)
|
||
|
||
### ❌ `/teacher/grades`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 200
|
||
- **错误信息**:
|
||
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/grades),权限隔离失效
|
||
|
||
### ❌ `/teacher/questions`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 200
|
||
- **错误信息**:
|
||
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/questions),权限隔离失效
|
||
|
||
### ❌ `/teacher/classes`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 200
|
||
- **重定向**: `http://localhost:3000/teacher/classes/my`
|
||
- **错误信息**:
|
||
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/classes/my),权限隔离失效
|
||
|
||
### ❌ `/teacher/attendance`
|
||
|
||
- **分类**: Cross-Role Access Control
|
||
- **HTTP状态**: 200
|
||
- **错误信息**:
|
||
- ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/attendance),权限隔离失效
|
||
|
||
---
|
||
|
||
## 九、测试覆盖范围
|
||
|
||
### 9.1 家长端路由(来自 `src/modules/layout/config/navigation.ts`)
|
||
|
||
- `/parent/dashboard` - 家长仪表盘
|
||
- `/parent/grades` - 子女成绩聚合页
|
||
- `/parent/attendance` - 子女考勤聚合页
|
||
- `/parent/children/[studentId]` - 单个子女详情页
|
||
- `/announcements` - 公告列表(家长有 `ANNOUNCEMENT_READ` 权限)
|
||
- `/messages` - 消息列表(家长有 `MESSAGE_READ` 权限)
|
||
- `/messages/compose` - 写消息
|
||
- `/profile` - 个人资料
|
||
- `/settings` - 设置
|
||
- `/settings/security` - 安全设置
|
||
|
||
### 9.2 跨角色访问保护测试
|
||
|
||
家长账号尝试访问以下路由,应被 `src/proxy.ts` 重定向回 `/parent/dashboard`:
|
||
- `/admin/*` - 管理员页面(需 `SCHOOL_MANAGE` 权限)
|
||
- `/teacher/*` - 教师页面(需 `EXAM_READ` 权限,家长虽有此权限但路由前缀仍会拦截教师专属页面)
|
||
- `/student/*` - 学生页面(需 `HOMEWORK_SUBMIT` 权限)
|
||
- `/management/*` - 管理页面(需 `GRADE_MANAGE` 权限)
|
||
|
||
### 9.3 功能完整性检查项
|
||
|
||
- 仪表盘:标题、问候语、快捷入口(Grades/Attendance/Announcements)、子女卡片、统计计数
|
||
- 子女详情页:返回按钮、姓名标题、邮箱掩码、作业摘要、成绩趋势、今日课表、View all 链接
|
||
- 侧边栏导航:仅显示家长相关菜单,不显示教师/管理员菜单
|
||
- 跨家庭隔离:访问非关联子女应被拒绝
|
||
|
||
---
|
||
|
||
*报告自动生成于 2026-06-20 12:28:43* |