diff --git a/auth/auth.php b/auth/auth.php index 83bdd9d..1545d9f 100644 --- a/auth/auth.php +++ b/auth/auth.php @@ -9,15 +9,17 @@ // // Po jeho načtení máš k dispozici tyto proměnné: // -// $auth_prihlasen ... true / false -// $auth_uzivatel['id'] ... ID přihlášeného uživatele -// $auth_uzivatel['email'] ... email přihlášeného uživatele -// $auth_uzivatel['admin'] ... true / false +// $auth_prihlasen ... true / false (vždy nastaveno) +// $auth_uzivatel['id'] ... ID přihlášeného uživatele (nebo null) +// $auth_uzivatel['email'] ... email přihlášeného uživatele (nebo null) +// $auth_uzivatel['admin'] ... true / false (vždy nastaveno) +// $auth_logout_html ... HTML formulář s tlačítkem odhlášení, +// nebo prázdný řetězec pokud není přihlášen +// +// Použití odhlašovacího tlačítka na chráněné stránce: +// +// echo $auth_logout_html; // -// Pokud je v config.php VYZADOVAT_PRIHLASENI = true a uživatel -// není přihlášen, bude automaticky přesměrován na přihlašovací -// stránku. Jinak se stránka zobrazí a ty si sám rozhodneš, -// co nepřihlášenému uživateli ukážeš. // ============================================================ require_once __DIR__ . '/config.php'; @@ -34,18 +36,20 @@ require_once __DIR__ . '/db.php'; // Secure = cookie se posílá jen přes HTTPS (pokud web běží na HTTPS) session_name(SESSION_NAZEV); session_set_cookie_params([ - 'lifetime' => 0, // 0 = cookie platí do zavření prohlížeče - // (trvalost zajišťuje remember me, ne session) + 'lifetime' => 0, // 0 = cookie platí do zavření prohlížeče + // (trvalost zajišťuje remember me, ne session) 'path' => '/', - 'httponly' => true, // JavaScript k cookie nemá přístup - 'samesite' => 'Strict', // ochrana před CSRF - // 'secure' => true, // odkomentuj pokud web běží na HTTPS + 'httponly' => true, // JavaScript k cookie nemá přístup + 'samesite' => 'Strict', // ochrana před CSRF + // 'secure' => true, // odkomentuj pokud web běží na HTTPS ]); session_start(); // ------------------------------------------------------------ // VÝCHOZÍ STAV – uživatel není přihlášen // ------------------------------------------------------------ +// Tyto hodnoty jsou nastaveny vždy – při každém načtení stránky. +// Teprve níže se případně přepíší na true / skutečné hodnoty. $auth_prihlasen = false; $auth_uzivatel = [ @@ -53,19 +57,17 @@ $auth_uzivatel = [ 'email' => null, 'admin' => false, ]; +$auth_logout_html = ''; // ------------------------------------------------------------ // KROK 1: Existuje platná session? // ------------------------------------------------------------ // Session je nejrychlejší způsob ověření – nevyžaduje dotaz do DB. -// Pokud session existuje a obsahuje uzivatel_id, uživatel je -// přihlášen. Session data jsou uložena na serveru, uživatel -// je nemůže zfalšovat. +// Session data jsou uložena na serveru, uživatel je nemůže zfalšovat. if (isset($_SESSION['uzivatel_id']) && isset($_SESSION['email'])) { // Kontrola expirace session (nečinnost) - // Pokud uživatel byl příliš dlouho neaktivní, session zrušíme if (isset($_SESSION['posledni_aktivita']) && (time() - $_SESSION['posledni_aktivita']) > SESSION_EXPIRACE) { @@ -121,15 +123,12 @@ if (!$auth_prihlasen && $stmt->execute([':selector' => $cookie_selector]); $zaznam = $stmt->fetch(); - // Příznak, zda je cookie platná $cookie_ok = false; if ($zaznam) { // Zkontrolujeme, zda token ještě nevypršel - $expiruje_timestamp = strtotime($zaznam['expiruje']); - - if (time() < $expiruje_timestamp) { + if (time() < strtotime($zaznam['expiruje'])) { // Ověříme tajný token pomocí password_verify(). // Tato funkce záměrně trvá stejně dlouho bez ohledu @@ -143,14 +142,19 @@ if (!$auth_prihlasen && if ($cookie_ok) { // Cookie je platná – obnovíme session - // Nejprve regenerujeme session ID (ochrana před session fixation) + // Regenerujeme session ID (ochrana před session fixation) session_regenerate_id(true); - $_SESSION['uzivatel_id'] = $zaznam['uzivatel_id']; - $_SESSION['email'] = $zaznam['email']; - $_SESSION['admin'] = (bool) $zaznam['admin']; + $_SESSION['uzivatel_id'] = $zaznam['uzivatel_id']; + $_SESSION['email'] = $zaznam['email']; + $_SESSION['admin'] = (bool) $zaznam['admin']; $_SESSION['posledni_aktivita'] = time(); + // Vygenerujeme CSRF token pokud ještě neexistuje + if (empty($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); + } + $auth_prihlasen = true; $auth_uzivatel = [ 'id' => $zaznam['uzivatel_id'], @@ -178,18 +182,17 @@ if (!$auth_prihlasen && 'path' => '/', 'httponly' => true, 'samesite' => 'Strict', - // 'secure' => true, // odkomentuj pokud web běží na HTTPS + // 'secure' => true, ]); setcookie('auth_token', $cookie_token, [ 'expires' => $nova_expirace, 'path' => '/', 'httponly' => true, 'samesite' => 'Strict', - // 'secure' => true, // odkomentuj pokud web běží na HTTPS + // 'secure' => true, ]); - // Smažeme staré (expirované) tokeny z DB - // Děláme to zde příležitostně, aby se DB neplnila starými záznamy + // Smažeme staré (expirované) tokeny z DB příležitostně $stmt3 = $pdo->prepare(" DELETE FROM `" . DB_TABULKA_TOKENY . "` WHERE `expiruje` < :ted @@ -198,8 +201,7 @@ if (!$auth_prihlasen && } else { - // Cookie je neplatná nebo expirovaná – smažeme ji z prohlížeče - // i případný záznam z DB (pokud selector existoval) + // Cookie je neplatná nebo expirovaná – smažeme ji if ($zaznam) { $stmt4 = $pdo->prepare(" DELETE FROM `" . DB_TABULKA_TOKENY . "` @@ -208,7 +210,6 @@ if (!$auth_prihlasen && $stmt4->execute([':id' => $zaznam['token_id']]); } - // Smažeme cookies nastavením expirace do minulosti setcookie('auth_selector', '', [ 'expires' => time() - 3600, 'path' => '/', @@ -230,18 +231,31 @@ if (!$auth_prihlasen && if (!$auth_prihlasen && VYZADOVAT_PRIHLASENI) { - // Uložíme URL aktuální stránky, aby se uživatel mohl po - // přihlášení vrátit tam, kde byl + // Uložíme URL aktuální stránky pro přesměrování po přihlášení $aktualni_url = $_SERVER['REQUEST_URI'] ?? ''; if (!empty($aktualni_url)) { $_SESSION['redirect_po_prihlaseni'] = $aktualni_url; } - // Přesměujeme na přihlašovací stránku header('Location: ' . AUTH_LOGIN_URL); exit; +} - // Pokud je VYZADOVAT_PRIHLASENI = false, skript pokračuje dál. - // Stránka pak sama rozhodne, co nepřihlášenému uživateli ukáže, - // pomocí proměnných $auth_prihlasen a $auth_uzivatel. +// ------------------------------------------------------------ +// PŘIPRAVENÝ HTML KÓD PRO ODHLAŠOVACÍ TLAČÍTKO +// ------------------------------------------------------------ +// Na chráněné stránce stačí napsat: +// +// echo $auth_logout_html; +// +// Pokud uživatel není přihlášen, proměnná je prázdný řetězec +// a nevypíše se nic. + +if ($auth_prihlasen) { + $auth_logout_html = + '
'; } \ No newline at end of file diff --git a/auth/config.php b/auth/config.php index bd55733..2da2f3a 100644 --- a/auth/config.php +++ b/auth/config.php @@ -50,6 +50,9 @@ define('PROJEKT_URL', 'https://example.com'); // Cesta k přihlašovací stránce (relativní od kořene projektu) define('AUTH_LOGIN_URL', '/auth/login.php'); +// Cesta k odhlašovací stránce (relativní od kořene projektu) +define('AUTH_LOGOUT_URL', '/auth/logout.php'); + // Cesta k hlavní stránce po přihlášení define('AUTH_REDIRECT_PO_PRIHLASENI', '/index.php');