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();