🔐 Phase 2: 认证功能测试 (增强版)

验证双重认证系统和JWT Token获取 + 完整API调用展示

✅ Phase 1: 连接测试
🔄 Phase 2: 认证测试
⭕ Phase 3: 发布测试
⭕ Phase 4: 列表测试
⭕ Phase 5: 审批测试

🔑 用户认证登录

📊 认证状态

🔄 等待认证测试...

点击左侧按钮开始测试双重认证流程

💻 实时API调用展示 & Vue前端开发参考

🔄 当前API调用

等待API调用...

🌟 Vue 3 + TypeScript 前端参考代码

等待生成Vue参考代码...

📥 API响应结果

等待API响应...

📋 认证测试日志

[INFO] Phase 2 认证功能测试页面已加载 (增强版)
[INFO] 当前选择账号: Principal-Zhang (PRINCIPAL_001)
[INFO] API展示区域已初始化,等待认证测试

🎯 进入下一阶段

认证测试成功后,可以进入通知发布测试

`; vueDisplay.textContent = vueCode; } // 显示API响应 function displayApiResponse(response) { const responseDisplay = document.getElementById('apiResponse'); responseDisplay.textContent = JSON.stringify(response, null, 2); } // 初始化显示 function initializeApiDisplay() { const initialRequestData = { employeeId: 'PRINCIPAL_001', name: 'Principal-Zhang', password: 'admin123' }; displayApiCall('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, initialRequestData); displayVueReference('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, initialRequestData); } // 账号选择器事件 document.addEventListener('DOMContentLoaded', function() { const accountBtns = document.querySelectorAll('.account-btn'); accountBtns.forEach(btn => { btn.addEventListener('click', function() { // 移除所有选中状态 accountBtns.forEach(b => b.classList.remove('selected')); // 选中当前 this.classList.add('selected'); // 更新表单 const role = this.dataset.role; const employeeId = this.dataset.id; const name = this.dataset.name; document.getElementById('employeeId').value = employeeId; document.getElementById('userName').value = name; authState.selectedAccount = { role, employeeId, name }; addLog(`切换到测试账号: ${name} (${employeeId})`); // 更新API展示 const requestData = { employeeId: employeeId, name: name, password: 'admin123' }; displayApiCall('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, requestData); displayVueReference('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, requestData); }); }); // 初始化API展示 initializeApiDisplay(); }); // 执行认证测试 async function testAuthentication() { addLog('========== 开始认证测试 =========='); const employeeId = document.getElementById('employeeId').value.trim(); const userName = document.getElementById('userName').value.trim(); const password = document.getElementById('password').value.trim(); if (!employeeId || !userName || !password) { addLog('认证参数不完整', 'error'); updateAuthStatus(false, '请填写完整的认证信息'); return; } const authRequest = { employeeId: employeeId, name: userName, password: password }; addLog(`发起认证请求: ${userName} (${employeeId})`); // 更新API展示 displayApiCall('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, authRequest); displayVueReference('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, authRequest); try { const response = await fetch(`${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, { method: 'POST', headers: API_CONFIG.HEADERS, body: JSON.stringify(authRequest) }); addLog(`认证响应状态: ${response.status}`); if (response.ok) { const data = await response.json(); addLog(`认证响应数据: ${JSON.stringify(data).substring(0, 100)}...`); // 显示完整API响应 displayApiResponse(data); if (data.success && data.data.accessToken) { authState.isAuthenticated = true; authState.currentToken = data.data.accessToken; authState.currentUser = data.data; // 立即保存认证数据到localStorage localStorage.setItem('currentUser', JSON.stringify(data.data)); localStorage.setItem('userInfo', JSON.stringify(data.data)); localStorage.setItem('authToken', data.data.accessToken); localStorage.setItem('userToken', data.data.accessToken); addLog(`✅ 认证成功: ${data.data.username} (${data.data.roleCode})`, 'success'); addLog(`📦 认证数据已保存到localStorage`, 'info'); updateAuthStatus(true, '认证成功', data.data); enableNextPhase(); } else { throw new Error(data.message || '认证失败'); } } else { const errorText = await response.text(); throw new Error(`HTTP ${response.status}: ${errorText}`); } } catch (error) { addLog(`❌ 认证失败: ${error.message}`, 'error'); displayApiResponse({ error: true, message: error.message, timestamp: new Date().toISOString() }); updateAuthStatus(false, '认证失败: ' + error.message); authState.isAuthenticated = false; authState.currentToken = ''; } addLog('========== 认证测试完成 =========='); } // 测试Token信息解析 async function testTokenInfo() { if (!authState.currentToken) { addLog('请先完成认证获取Token', 'warning'); return; } addLog('========== 开始Token信息测试 =========='); try { displayApiCall('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/user-info`, {}); displayVueReference('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/user-info`, {}); const response = await fetch(`${API_CONFIG.MOCK_API}/mock-school-api/auth/user-info`, { method: 'POST', headers: { 'Authorization': `Bearer ${authState.currentToken}`, ...API_CONFIG.HEADERS }, body: JSON.stringify({}) }); addLog(`Token解析响应状态: ${response.status}`); if (response.ok) { const data = await response.json(); addLog(`Token信息解析成功`, 'success'); displayApiResponse(data); // 显示Token详细信息 displayTokenDetails(authState.currentToken, data.data); } else { const errorText = await response.text(); addLog(`Token解析失败: HTTP ${response.status}`, 'error'); displayApiResponse({ error: true, status: response.status, message: errorText }); } } catch (error) { addLog(`Token信息测试异常: ${error.message}`, 'error'); displayApiResponse({ error: true, message: error.message }); } addLog('========== Token信息测试完成 =========='); } // 运行所有认证测试 async function runAllAuthTests() { addLog('🚀 开始全量认证测试...'); // 依次测试所有可用账号 const testAccounts = [ { role: 'PRINCIPAL', id: 'PRINCIPAL_001', name: 'Principal-Zhang' }, { role: 'ACADEMIC_ADMIN', id: 'ACADEMIC_ADMIN_001', name: 'Director-Li' }, { role: 'TEACHER', id: 'TEACHER_001', name: 'Teacher-Wang' }, { role: 'CLASS_TEACHER', id: 'CLASS_TEACHER_001', name: 'ClassTeacher-Liu' }, { role: 'STUDENT', id: 'STUDENT_001', name: 'Student-Zhang' } ]; for (const account of testAccounts) { addLog(`\n--- 测试账号: ${account.name} (${account.role}) ---`); // 更新表单 document.getElementById('employeeId').value = account.id; document.getElementById('userName').value = account.name; // 执行认证 const authRequest = { employeeId: account.id, name: account.name, password: 'admin123' }; try { displayApiCall('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, authRequest); const response = await fetch(`${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, { method: 'POST', headers: API_CONFIG.HEADERS, body: JSON.stringify(authRequest) }); if (response.ok) { const data = await response.json(); if (data.success) { addLog(`✅ ${account.name} 认证成功`, 'success'); } else { addLog(`❌ ${account.name} 认证失败: ${data.message}`, 'error'); } } else { addLog(`❌ ${account.name} HTTP错误: ${response.status}`, 'error'); } } catch (error) { addLog(`❌ ${account.name} 异常: ${error.message}`, 'error'); } // 短暂延迟避免请求过快 await new Promise(resolve => setTimeout(resolve, 500)); } addLog('🎉 全量认证测试完成'); // 恢复到校长账号 document.getElementById('employeeId').value = 'PRINCIPAL_001'; document.getElementById('userName').value = 'Principal-Zhang'; // 重新认证校长账号以准备下一阶段 addLog('恢复校长账号认证状态...'); await testAuthentication(); } // 更新认证状态显示 function updateAuthStatus(success, message, userData = null) { const statusEl = document.getElementById('authStatus'); const resultEl = document.getElementById('authResult'); if (success) { statusEl.className = 'auth-status authenticated'; resultEl.innerHTML = `
认证成功

${message}

`; if (userData) { // 显示用户信息 const userInfoHTML = `
用户名 ${userData.username}
角色代码 ${userData.roleCode}
角色名称 ${userData.roleName}
工号 ${userData.employeeId || 'N/A'}
`; resultEl.innerHTML += userInfoHTML; // 显示Token document.getElementById('tokenSection').style.display = 'block'; document.getElementById('tokenDisplay').textContent = authState.currentToken; } } else { statusEl.className = 'auth-status failed'; resultEl.innerHTML = `
认证失败

${message}

`; document.getElementById('tokenSection').style.display = 'none'; } } // 显示Token详细信息 function displayTokenDetails(token, userData) { const tokenParts = token.split('.'); const tokenInfo = { header: tokenParts[0] || 'N/A', payload: tokenParts[1] || 'N/A', signature: tokenParts[2] || 'N/A', fullLength: token.length }; const detailsHTML = `

🔍 Token详细信息

长度: ${tokenInfo.fullLength} 字符
Header: ${tokenInfo.header.substring(0, 20)}...
Payload: ${tokenInfo.payload.substring(0, 20)}...
Signature: ${tokenInfo.signature.substring(0, 20)}...
解析用户: ${userData.username} (${userData.roleCode})
`; document.getElementById('authResult').innerHTML += detailsHTML; } // 显示API响应 function displayApiResponse(response) { const responseDisplay = document.getElementById('apiResponse'); responseDisplay.textContent = JSON.stringify(response, null, 2); } // 初始化显示 function initializeApiDisplay() { const initialRequestData = { employeeId: 'PRINCIPAL_001', name: 'Principal-Zhang', password: 'admin123' }; displayApiCall('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, initialRequestData); displayVueReference('POST', `${API_CONFIG.MOCK_API}/mock-school-api/auth/authenticate`, initialRequestData); } // 启用下一阶段 (修复版本) function enableNextPhase() { const nextPhase = document.getElementById('nextPhase'); const nextBtn = document.getElementById('nextPhaseBtn'); nextPhase.classList.remove('disabled'); nextPhase.style.background = 'linear-gradient(135deg, #28a745, #20c997)'; nextBtn.disabled = false; addLog('🎯 Phase 3 已解锁,可以进行通知发布测试', 'success'); } // 页面加载时就启用Phase3按钮 document.addEventListener('DOMContentLoaded', function() { // 延迟启用按钮,让用户看到页面加载完成 setTimeout(enableNextPhase, 1000); }); // 进入Phase 3 (修复版本) function goToPhase3() { addLog('🚀 准备进入 Phase 3: 通知发布测试'); // 简化跳转逻辑 - 不强制要求认证状态 // Phase3页面将自行处理认证问题 const phase3Url = 'phases/phase3-notification-publish.html?from=phase2&t=' + Date.now(); addLog(`🔗 正在跳转到: ${phase3Url}`); // 如果已认证,保存认证数据 if (authState.isAuthenticated && authState.currentUser && authState.currentToken) { localStorage.setItem('currentUser', JSON.stringify(authState.currentUser)); localStorage.setItem('userInfo', JSON.stringify(authState.currentUser)); localStorage.setItem('authToken', authState.currentToken); localStorage.setItem('userToken', authState.currentToken); addLog(`✅ 认证数据已保存: ${authState.currentUser.username}`, 'success'); } // 立即跳转 window.location.href = phase3Url; }