fetchOne( 'SELECT id FROM students WHERE class_id = ? AND display_name = ? AND deleted_at IS NULL', [$classId, $displayName] ); if ($row) $studentId = (int)$row['id']; } $db->execute( 'INSERT INTO student_sessions (id, class_id, display_name, student_id) VALUES (?, ?, ?, ?)', [$uuid, $classId, $displayName, $studentId] ); setcookie(self::COOKIE_NAME, $uuid, [ 'expires' => time() + self::COOKIE_TTL, 'path' => BASE_PATH . '/', 'samesite' => 'Lax', 'secure' => IS_PRODUCTION, 'httponly' => true, ]); return $uuid; } /** API-Guard: 401 wenn keine Session */ public static function requireStudent(): string { $id = self::studentId(); if (!$id) { http_response_code(401); echo json_encode(['error' => 'Keine Session']); exit; } return $id; } /** Lehrer eingeloggt? (startet die Session lazy — Aufrufer müssen nicht) */ public static function teacherId(): ?int { self::start(); return $_SESSION['teacher_id'] ?? null; } /** Lehrer-Login */ public static function loginTeacher(int $teacherId): void { self::start(); $_SESSION['teacher_id'] = $teacherId; } /** Lehrer-Guard: 401 wenn nicht eingeloggt */ public static function requireTeacher(): int { $id = self::teacherId(); if (!$id) { http_response_code(401); echo json_encode(['error' => 'Nicht eingeloggt']); exit; } return $id; } // ── Admin (Super-Admin nach 2FA) ──────────────────────────────────── // Einheitlicher Zugang wie beim Lehrer, damit der spätere JWT+Redis- // Umschalter (AUTH_BACKEND) an EINER Stelle greift statt an jedem Endpoint. /** Admin eingeloggt (2FA abgeschlossen)? */ public static function adminId(): ?int { self::start(); return $_SESSION['admin_id'] ?? null; } /** Admin-Login abschließen (nach erfolgreicher 2FA). */ public static function loginAdmin(int $adminId): void { self::start(); $_SESSION['admin_id'] = $adminId; } /** Admin-Logout — inkl. offener 2FA-Phase (admin_pending). */ public static function logoutAdmin(): void { self::start(); unset($_SESSION['admin_id'], $_SESSION['admin_pending']); } /** Admin-Guard: 403 wenn nicht eingeloggt. */ public static function requireAdmin(): int { $id = self::adminId(); if (!$id) { http_response_code(403); echo json_encode(['error' => 'Nur Admin']); exit; } return $id; } public static function logout(): void { self::start(); session_destroy(); setcookie(self::COOKIE_NAME, '', [ 'expires' => 1, 'path' => BASE_PATH . '/', 'samesite' => 'Lax', 'secure' => IS_PRODUCTION, 'httponly' => true, ]); } }