技术栈:Go (Gin + GORM) + PHP + MySQL 5.7 + Redis 主要功能: - 多班级完全隔离(class_id 贯穿全系统) - 后端从 Python FastAPI 重写为 Go Gin(端口 56789) - 超级管理员独立登录(env 配置路径,默认账密 admin/Admin123) - 科任老师/课代表新角色 - 课代表作业管理页面 - 排行榜分项排行(操行分/考勤/作业) - 角色加减分上下限由班主任配置 - 家长改密功能(可开关) - 班级角色按需开关 - 宿舍号格式:南0-000 - 周度/月度重置功能 - MySQL 5.7 兼容 - Nginx 反向代理部署 开发者: Canglan 版权归属: Sea Network Technology Studio 许可证: Apache License 2.0
219 lines
6.0 KiB
PHP
219 lines
6.0 KiB
PHP
<?php
|
||
/**
|
||
* 多班级版班级管理系统 - Session 保存接口
|
||
*
|
||
* 开发者: Canglan
|
||
* 联系方式: admin@sea-studio.top
|
||
* 版权归属: Sea Network Technology Studio
|
||
* 许可证: Apache License 2.0
|
||
*
|
||
* 版权所有 © Sea Network Technology Studio
|
||
*
|
||
* 说明:登录成功后,前端调用此接口将用户信息同步到 PHP Session
|
||
*/
|
||
|
||
// 引入配置文件以初始化 Session
|
||
require_once __DIR__ . '/../config.php';
|
||
|
||
// 设置响应头
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
|
||
// 仅允许同源请求
|
||
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
||
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
||
|
||
// 处理预检请求
|
||
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();
|
||
}
|
||
|
||
// CSRF 防护:验证 Origin/Referer 头确保同源请求
|
||
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||
$referer = $_SERVER['HTTP_REFERER'] ?? '';
|
||
$host = $_SERVER['HTTP_HOST'] ?? '';
|
||
$serverName = $_SERVER['SERVER_NAME'] ?? '';
|
||
|
||
if (!empty($origin)) {
|
||
$parsedOrigin = parse_url($origin, PHP_URL_HOST);
|
||
if ($parsedOrigin !== $host && $parsedOrigin !== $serverName) {
|
||
http_response_code(403);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '跨域请求被拒绝'
|
||
]);
|
||
exit();
|
||
}
|
||
} elseif (!empty($referer)) {
|
||
$parsedReferer = parse_url($referer, PHP_URL_HOST);
|
||
if ($parsedReferer !== $host && $parsedReferer !== $serverName) {
|
||
http_response_code(403);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '跨域请求被拒绝'
|
||
]);
|
||
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', 'super_admin'];
|
||
if (!in_array($data['user_type'], $validUserTypes)) {
|
||
http_response_code(400);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '无效的用户类型'
|
||
]);
|
||
exit();
|
||
}
|
||
|
||
// 验证 JWT Token
|
||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
||
if (empty($authHeader) || !preg_match('/^Bearer\s+(.+)$/i', $authHeader, $matches)) {
|
||
http_response_code(401);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '缺少认证令牌'
|
||
]);
|
||
exit();
|
||
}
|
||
|
||
$token = $matches[1];
|
||
$apiUrl = API_BASE_URL . '/api/auth/me';
|
||
|
||
$ch = curl_init();
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_URL => $apiUrl,
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_TIMEOUT => 10,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Authorization: Bearer ' . $token,
|
||
'Content-Type: application/json'
|
||
],
|
||
CURLOPT_SSL_VERIFYPEER => true,
|
||
CURLOPT_SSL_VERIFYHOST => 2
|
||
]);
|
||
|
||
$apiResponse = curl_exec($ch);
|
||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||
curl_close($ch);
|
||
|
||
if ($httpCode !== 200 || empty($apiResponse)) {
|
||
http_response_code(401);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '认证令牌无效或已过期'
|
||
]);
|
||
exit();
|
||
}
|
||
|
||
$tokenData = json_decode($apiResponse, true);
|
||
if (!$tokenData || !isset($tokenData['success']) || !$tokenData['success']) {
|
||
http_response_code(401);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '认证验证失败'
|
||
]);
|
||
exit();
|
||
}
|
||
|
||
// 验证 token 中的 user_id 与请求数据中的 user_id 一致
|
||
$tokenUserId = $tokenData['data']['user_id'] ?? null;
|
||
if ($tokenUserId === null || intval($tokenUserId) !== intval($data['user_id'])) {
|
||
http_response_code(403);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '身份验证不匹配'
|
||
]);
|
||
exit();
|
||
}
|
||
|
||
// 从后端 JWT 解析权威数据(不信任客户端传入的 user_type/role)
|
||
$tokenData_user = $tokenData['data'];
|
||
// 登录成功后重新生成 Session ID,防止 Session 固定攻击
|
||
session_regenerate_id(true);
|
||
$_SESSION['user_id'] = intval($tokenData_user['user_id']);
|
||
$_SESSION['user_type'] = $tokenData_user['user_type'];
|
||
$_SESSION['username'] = $tokenData_user['username'];
|
||
$_SESSION['real_name'] = $tokenData_user['real_name'] ?? '';
|
||
$_SESSION['role'] = $tokenData_user['role'] ?? '';
|
||
$_SESSION['class_id'] = $tokenData_user['class_id'] ?? null;
|
||
$_SESSION['class_name'] = $tokenData_user['class_name'] ?? '';
|
||
$_SESSION['login_time'] = time();
|
||
$_SESSION['jwt_token'] = $token;
|
||
// 如果是学生,额外设置 student_id(仅从 JWT 解析,不信任客户端传入值)
|
||
if ($_SESSION['user_type'] === 'student') {
|
||
$studentId = $tokenData_user['student_id'] ?? null;
|
||
if (empty($studentId)) {
|
||
http_response_code(400);
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => '学生类型必须提供 student_id'
|
||
]);
|
||
exit();
|
||
}
|
||
$_SESSION['student_id'] = $studentId;
|
||
}
|
||
|
||
// 保存 Session
|
||
session_write_close();
|
||
|
||
// 返回成功响应
|
||
http_response_code(200);
|
||
echo json_encode([
|
||
'success' => true,
|
||
'message' => 'Session 保存成功'
|
||
]);
|
||
exit(); |