166 lines
5.7 KiB
PHP
166 lines
5.7 KiB
PHP
<?php
|
||
/**
|
||
* Authentifizierung – getrennte Sessions für Kunden (users) und Mitarbeiter (staff)
|
||
*/
|
||
|
||
// ---------------------------------------------------------------
|
||
// Kunden-Auth
|
||
// ---------------------------------------------------------------
|
||
|
||
function customer_login(array $user): void
|
||
{
|
||
session_regenerate_id(true);
|
||
$_SESSION['user_id'] = $user['id'];
|
||
}
|
||
|
||
function customer_logout(): void
|
||
{
|
||
unset($_SESSION['user_id']);
|
||
}
|
||
|
||
function current_user(): ?array
|
||
{
|
||
if (empty($_SESSION['user_id'])) {
|
||
return null;
|
||
}
|
||
static $cache = null;
|
||
if ($cache !== null) {
|
||
return $cache;
|
||
}
|
||
$stmt = get_db()->prepare('SELECT * FROM users WHERE id = ?');
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
$user = $stmt->fetch();
|
||
return $cache = ($user ?: null);
|
||
}
|
||
|
||
function require_customer_login(): array
|
||
{
|
||
$user = current_user();
|
||
if (!$user) {
|
||
flash('error', 'Bitte melden Sie sich an, um fortzufahren.');
|
||
redirect(base_path() . '/login.php');
|
||
}
|
||
return $user;
|
||
}
|
||
|
||
// ---------------------------------------------------------------
|
||
// Mitarbeiter-Auth
|
||
// ---------------------------------------------------------------
|
||
|
||
function staff_login(array $staff): void
|
||
{
|
||
session_regenerate_id(true);
|
||
$_SESSION['staff_id'] = $staff['id'];
|
||
$_SESSION['staff_last_activity'] = time();
|
||
staff_touch_activity(get_db(), (int) $staff['id']);
|
||
}
|
||
|
||
function staff_logout(): void
|
||
{
|
||
// Automatische Zeiterfassung: offene Arbeits-Sitzungen beim Logout sofort
|
||
// abschließen, statt bis zum nächsten Stale-Sweep (Auto-Cron) zu warten.
|
||
if (!empty($_SESSION['staff_id'])) {
|
||
finalize_all_sessions_for_staff(get_db(), (int) $_SESSION['staff_id']);
|
||
}
|
||
unset($_SESSION['staff_id']);
|
||
}
|
||
|
||
function current_staff(): ?array
|
||
{
|
||
if (empty($_SESSION['staff_id'])) {
|
||
return null;
|
||
}
|
||
static $cache = null;
|
||
if ($cache !== null) {
|
||
return $cache;
|
||
}
|
||
$stmt = get_db()->prepare('SELECT * FROM staff WHERE id = ? AND is_active = 1');
|
||
$stmt->execute([$_SESSION['staff_id']]);
|
||
$staff = $stmt->fetch();
|
||
return $cache = ($staff ?: null);
|
||
}
|
||
|
||
function require_staff_login(): array
|
||
{
|
||
$staff = current_staff();
|
||
if (!$staff) {
|
||
// War die Sitzung gerade wegen Inaktivität abgelaufen (ein Hintergrund-Abruf hat sie schon beendet), den Grund nennen
|
||
if (!empty($_SESSION['staff_timed_out'])) {
|
||
unset($_SESSION['staff_timed_out']);
|
||
flash('error', 'Sie wurden wegen Inaktivität abgemeldet. Bitte melden Sie sich erneut an.');
|
||
} else {
|
||
flash('error', 'Bitte melden Sie sich an, um fortzufahren.');
|
||
}
|
||
redirect(staff_base_path() . '/login.php');
|
||
}
|
||
// Inaktivitäts-Timeout
|
||
$timeout = (int)(get_setting('staff_session_timeout', '30') ?: 30); // Minuten
|
||
$last = $_SESSION['staff_last_activity'] ?? 0;
|
||
$userNavigation = staff_is_user_navigation();
|
||
if ($last && (time() - $last) > ($timeout * 60)) {
|
||
staff_logout();
|
||
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
|
||
$_SESSION['staff_timed_out'] = time(); // merken, damit die Anmeldeseite den Grund nennen kann (siehe oben)
|
||
if (!staff_is_document_request()) {
|
||
// Hintergrund-Abruf (Aktualisierung der Liste, Chat-Abfrage …): kurze Antwort statt Weiterleitung auf die Anmeldeseite.
|
||
// Das Laden einer Seite dagegen führt immer zur Anmeldung, auch wenn der Browser es selbst ausgelöst hat (Tab neu geladen).
|
||
http_response_code(401);
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
echo json_encode(['error' => 'Session abgelaufen', 'sessionExpired' => true]);
|
||
exit;
|
||
}
|
||
unset($_SESSION['staff_timed_out']);
|
||
$_SESSION['flash'] = [['type'=>'error','message'=>'Sie wurden wegen Inaktivität abgemeldet. Bitte melden Sie sich erneut an.']];
|
||
redirect('/staff/login.php');
|
||
}
|
||
// Nur echte Bedienung hält die Sitzung am Leben: ein vom Nutzer ausgelöster Seitenaufruf oder der Ping der Seite bei Klicks und
|
||
// Tastatureingaben (staff/session_ping.php). Hintergrund-Abfragen der offenen Seiten (Listen, Chat, Anwesenheit alle paar
|
||
// Sekunden) zählen nicht, sonst würde eine offene Seite die Sitzung ewig verlängern und die Abmeldung nie greifen.
|
||
if ($userNavigation) {
|
||
$_SESSION['staff_last_activity'] = time();
|
||
staff_touch_activity(get_db(), (int) $staff['id']);
|
||
}
|
||
|
||
// "Eingebauter" Ersatz für echte Server-Cronjobs (siehe includes/pseudo_cron.php):
|
||
// bei jeder authentifizierten Backend-Anfrage werden fällige Jobs im Hintergrund geprüft.
|
||
pseudo_cron_schedule_background();
|
||
|
||
return $staff;
|
||
}
|
||
|
||
function require_admin(): array
|
||
{
|
||
$staff = require_staff_login();
|
||
if ($staff['role'] !== 'admin') {
|
||
flash('error', 'Diese Funktion ist nur für Administratoren verfügbar.');
|
||
redirect(staff_base_path() . '/reports.php');
|
||
}
|
||
return $staff;
|
||
}
|
||
|
||
/**
|
||
* Wie require_admin(), lässt aber zusätzlich Agenten mit einer benutzerdefinierten Rolle
|
||
* durch, die genau dieses Adminportal-Recht zugewiesen bekommen haben ("Co-Admin" für
|
||
* einzelne Bereiche, siehe admin_section_permissions() / staff/roles.php).
|
||
*/
|
||
function require_admin_or_permission(string $permission): array
|
||
{
|
||
$staff = require_staff_login();
|
||
if ($staff['role'] !== 'admin' && !has_permission($staff, $permission)) {
|
||
flash('error', 'Für diese Funktion fehlt die erforderliche Berechtigung.');
|
||
redirect(staff_base_path() . '/reports.php');
|
||
}
|
||
return $staff;
|
||
}
|
||
|
||
/** Pfad-Helfer, damit Includes unabhängig vom Aufrufort funktionieren */
|
||
function base_path(): string
|
||
{
|
||
return '';
|
||
}
|
||
|
||
function staff_base_path(): string
|
||
{
|
||
return '/staff';
|
||
}
|