# 家长端 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`
跨角色访问被权限系统拦截 | | ✅ | `/admin/school` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fadmin%2Fschool&reason=forbidden`
跨角色访问被权限系统拦截 | | ❌ | `/teacher/dashboard` | 500 | failed | 错误: 跨角色访问返回 HTTP 500(应被重定向拦截)
错误: Failed to load resource: the server responded with a status of 500 (Internal Server Error) | | ❌ | `/teacher/exams` | 200 | failed | 重定向: `/teacher/exams/all`
错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 URL: http://localhost:3000/teacher/exams/all),权限隔离失效
错误: %o | | ❌ | `/teacher/homework` | 500 | failed | 重定向: `/teacher/homework/assignments`
错误: 跨角色访问返回 HTTP 500(应被重定向拦截)
错误: 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`
错误: ⚠️ 安全漏洞:家长成功访问了受限页面(最终 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`
跨角色访问被权限系统拦截 | | ✅ | `/student/learning` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Flearning&reason=forbidden`
跨角色访问被权限系统拦截 | | ✅ | `/student/grades` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fgrades&reason=forbidden`
跨角色访问被权限系统拦截 | | ✅ | `/student/attendance` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fstudent%2Fattendance&reason=forbidden`
跨角色访问被权限系统拦截 | | ✅ | `/management/grade/classes` | 200 | passed | 重定向: `/parent/dashboard?from=%2Fmanagement%2Fgrade%2Fclasses&reason=forbidden`
跨角色访问被权限系统拦截 | ### 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*