v0.3测试
This commit is contained in:
19
.cospec/plan/changes/fix-login-session-sync/proposal.md
Normal file
19
.cospec/plan/changes/fix-login-session-sync/proposal.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 变更:修复登录状态问题(Session与Token同步)
|
||||||
|
|
||||||
|
## 原因
|
||||||
|
用户反馈"登录后无法保存token,登录后跳转回登录页"。经深度探索发现,系统存在 Session(PHP后端)+ Token(API后端)双轨制认证架构:
|
||||||
|
|
||||||
|
- **登录API** (`/api/auth/login`) 返回 JWT Token,前端存入 localStorage
|
||||||
|
- **Dashboard页面** 检查 PHP Session (`$_SESSION['user_id']`)
|
||||||
|
- **问题根因**:登录成功时只设置了 localStorage 中的 Token,没有同步设置 PHP Session,导致 dashboard 页面的 Session 检查失败,跳转回登录页
|
||||||
|
|
||||||
|
## 变更内容
|
||||||
|
- **新建** `frontend/api/save_session.php`:PHP Session 保存接口
|
||||||
|
- **修改** `frontend/index.php`:登录成功后调用 save_session.php 同步设置 PHP Session
|
||||||
|
- **修改** `frontend/config.php`:添加 API_BASE_URL 配置(如果缺失)
|
||||||
|
|
||||||
|
## 影响
|
||||||
|
- **受影响的规范**:登录认证流程
|
||||||
|
- **受影响的代码**:
|
||||||
|
- `frontend/index.php`:登录成功后增加同步Session逻辑
|
||||||
|
- `frontend/api/save_session.php`:新建,用于接收登录信息并设置PHP Session
|
||||||
37
.cospec/plan/changes/fix-login-session-sync/task.md
Normal file
37
.cospec/plan/changes/fix-login-session-sync/task.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
## 实施
|
||||||
|
|
||||||
|
- [ ] 1.1 创建 `frontend/api/save_session.php` Session 同步接口
|
||||||
|
【目标对象】`frontend/api/save_session.php`
|
||||||
|
【修改目的】提供接收前端登录信息并设置 PHP Session 的接口,解决登录后跳转回登录页的问题
|
||||||
|
【修改方式】新建 PHP 文件,实现 Session 设置逻辑
|
||||||
|
【相关依赖】`frontend/config.php`(用于引入必要的常量定义)
|
||||||
|
【修改内容】
|
||||||
|
- 文件顶部添加 `<?php` 声明
|
||||||
|
- 引入 config.php:`require_once __DIR__ . '/../config.php';`
|
||||||
|
- 启用 Session:`session_start();`
|
||||||
|
- 设置 CORS 头(如果需要跨域):`header('Content-Type: application/json');`
|
||||||
|
- 接收 POST 请求的 JSON 数据(user_id, user_type, username, real_name, student_id)
|
||||||
|
- 将用户数据存入 `$_SESSION` 变量
|
||||||
|
- 返回 JSON 响应:`{success: true}` 或错误信息
|
||||||
|
- 添加错误处理:JSON 解析失败、缺少必要字段等情况的处理
|
||||||
|
|
||||||
|
- [ ] 1.2 修改 `frontend/index.php` 登录成功逻辑
|
||||||
|
【目标对象】`frontend/index.php:84-87`(localStorage.setItem 和 window.location.href 所在区域)
|
||||||
|
【修改目的】登录成功后同步设置 PHP Session,解决 dashboard 页面 Session 检查失败的问题
|
||||||
|
【修改方式】在 window.location.href 跳转前,增加 fetch 调用 save_session.php
|
||||||
|
【相关依赖】`frontend/api/save_session.php`
|
||||||
|
【修改内容】
|
||||||
|
- 在 `localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(data.data));` 之后、`window.location.href = data.data.redirect;` 之前
|
||||||
|
- 增加 `await fetch('/api/save_session.php', {...})` 调用
|
||||||
|
- 将登录 API 返回的 user_id、user_type、username、real_name、student_id 等数据作为请求体发送
|
||||||
|
- 使用 async/await 等待 Session 设置完成后再执行跳转
|
||||||
|
- 添加错误处理:fetch 失败时记录错误但不影响跳转流程
|
||||||
|
|
||||||
|
- [ ] 1.3 验证修复效果
|
||||||
|
【验证方式】
|
||||||
|
- 清除浏览器 localStorage 和 Cookie
|
||||||
|
- 使用学生账号/家长账号/管理员账号执行登录操作
|
||||||
|
- 登录成功后应正常进入对应角色的 dashboard 页面,不再跳转回登录页
|
||||||
|
- 检查浏览器开发者工具 Network 面板,确认 `/api/save_session.php` 请求成功(HTTP 200)
|
||||||
|
- 检查浏览器 Cookies 中有 PHP Session ID(如 PHPSESSID)
|
||||||
|
- 在 dashboard 页面刷新,确认 Session 认证仍然有效
|
||||||
117
frontend/api/save_session.php
Normal file
117
frontend/api/save_session.php
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* 班级操行分管理系统 - Session 保存接口
|
||||||
|
*
|
||||||
|
* 开发者: Canglan
|
||||||
|
* 联系方式: admin@sea-studio.top
|
||||||
|
* 版权归属: Sea Network Technology Studio
|
||||||
|
* 许可证: MIT License
|
||||||
|
*
|
||||||
|
* 版权所有 © Sea Network Technology Studio
|
||||||
|
*
|
||||||
|
* 说明:登录成功后,前端调用此接口将用户信息同步到 PHP Session
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 引入配置文件以初始化 Session
|
||||||
|
require_once __DIR__ . '/../config.php';
|
||||||
|
|
||||||
|
// 设置响应头
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// 允许跨域(如果需要)
|
||||||
|
header('Access-Control-Allow-Origin: *');
|
||||||
|
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
||||||
|
header('Access-Control-Allow-Headers: Content-Type');
|
||||||
|
|
||||||
|
// 处理预检请求
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||||
|
http_response_code(200);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只允许 POST 请求
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => '仅支持 POST 请求'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取原始输入
|
||||||
|
$input = file_get_contents('php://input');
|
||||||
|
|
||||||
|
if (empty($input)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => '请求数据为空'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 JSON 数据
|
||||||
|
$data = json_decode($input, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'JSON 解析失败: ' . json_last_error_msg()
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证必要字段
|
||||||
|
$requiredFields = ['user_id', 'user_type', 'username'];
|
||||||
|
$missingFields = [];
|
||||||
|
|
||||||
|
foreach ($requiredFields as $field) {
|
||||||
|
if (!isset($data[$field]) || empty($data[$field])) {
|
||||||
|
$missingFields[] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($missingFields)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => '缺少必要字段: ' . implode(', ', $missingFields)
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证 user_type 是否合法
|
||||||
|
$validUserTypes = ['student', 'parent', 'admin'];
|
||||||
|
if (!in_array($data['user_type'], $validUserTypes)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => '无效的用户类型'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 Session 变量
|
||||||
|
$_SESSION['user_id'] = $data['user_id'];
|
||||||
|
$_SESSION['user_type'] = $data['user_type'];
|
||||||
|
$_SESSION['username'] = $data['username'];
|
||||||
|
$_SESSION['real_name'] = $data['real_name'] ?? '';
|
||||||
|
$_SESSION['login_time'] = time();
|
||||||
|
|
||||||
|
// 如果是学生,额外设置 student_id(与 user_id 相同)
|
||||||
|
if ($data['user_type'] === 'student') {
|
||||||
|
$_SESSION['student_id'] = $data['user_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存 Session
|
||||||
|
session_write_close();
|
||||||
|
|
||||||
|
// 返回成功响应
|
||||||
|
http_response_code(200);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Session 保存成功'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
@@ -82,9 +82,34 @@ if (isset($_SESSION['user_id']) && isset($_SESSION['user_type'])) {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success && data.data) {
|
if (data.success && data.data) {
|
||||||
localStorage.setItem(JWT_STORAGE_KEY, data.data.token);
|
const userData = data.data;
|
||||||
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(data.data));
|
|
||||||
window.location.href = data.data.redirect;
|
// 保存 Token 和用户信息到 localStorage
|
||||||
|
localStorage.setItem(JWT_STORAGE_KEY, userData.token);
|
||||||
|
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(userData));
|
||||||
|
|
||||||
|
// 同步设置 PHP Session(保持 Session + Token 双轨制认证)
|
||||||
|
try {
|
||||||
|
const sessionResponse = await fetch('/api/save_session.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
user_id: userData.user_id,
|
||||||
|
user_type: userData.user_type,
|
||||||
|
username: userData.username,
|
||||||
|
real_name: userData.real_name
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sessionResponse.ok) {
|
||||||
|
console.warn('Session 同步失败,但继续跳转');
|
||||||
|
}
|
||||||
|
} catch (sessionError) {
|
||||||
|
console.warn('Session 同步异常:', sessionError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转到对应端首页
|
||||||
|
window.location.href = userData.redirect;
|
||||||
} else {
|
} else {
|
||||||
showError(data.message || '登录失败');
|
showError(data.message || '登录失败');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user