[FÁZE-1][config] Přidána konstanta AUTH_LOGOUT_URL

[FÁZE-1][auth] Přidána proměnná $auth_logout_html s připraveným odhlašovacím formulářem
This commit is contained in:
stepan
2026-03-17 00:02:43 +01:00
parent 7663fdab77
commit 220124a54a
2 changed files with 55 additions and 38 deletions
+45 -31
View File
@@ -9,15 +9,17 @@
// //
// Po jeho načtení máš k dispozici tyto proměnné: // Po jeho načtení máš k dispozici tyto proměnné:
// //
// $auth_prihlasen ... true / false // $auth_prihlasen ... true / false (vždy nastaveno)
// $auth_uzivatel['id'] ... ID přihlášeného uživatele // $auth_uzivatel['id'] ... ID přihlášeného uživatele (nebo null)
// $auth_uzivatel['email'] ... email přihlášeného uživatele // $auth_uzivatel['email'] ... email přihlášeného uživatele (nebo null)
// $auth_uzivatel['admin'] ... true / false // $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'; require_once __DIR__ . '/config.php';
@@ -46,6 +48,8 @@ session_start();
// ------------------------------------------------------------ // ------------------------------------------------------------
// VÝCHOZÍ STAV uživatel není přihlášen // 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_prihlasen = false;
$auth_uzivatel = [ $auth_uzivatel = [
@@ -53,19 +57,17 @@ $auth_uzivatel = [
'email' => null, 'email' => null,
'admin' => false, 'admin' => false,
]; ];
$auth_logout_html = '';
// ------------------------------------------------------------ // ------------------------------------------------------------
// KROK 1: Existuje platná session? // KROK 1: Existuje platná session?
// ------------------------------------------------------------ // ------------------------------------------------------------
// Session je nejrychlejší způsob ověření nevyžaduje dotaz do DB. // Session je nejrychlejší způsob ověření nevyžaduje dotaz do DB.
// Pokud session existuje a obsahuje uzivatel_id, uživatel je // Session data jsou uložena na serveru, uživatel je nemůže zfalšovat.
// přihlášen. Session data jsou uložena na serveru, uživatel
// je nemůže zfalšovat.
if (isset($_SESSION['uzivatel_id']) && isset($_SESSION['email'])) { if (isset($_SESSION['uzivatel_id']) && isset($_SESSION['email'])) {
// Kontrola expirace session (nečinnost) // Kontrola expirace session (nečinnost)
// Pokud uživatel byl příliš dlouho neaktivní, session zrušíme
if (isset($_SESSION['posledni_aktivita']) && if (isset($_SESSION['posledni_aktivita']) &&
(time() - $_SESSION['posledni_aktivita']) > SESSION_EXPIRACE) { (time() - $_SESSION['posledni_aktivita']) > SESSION_EXPIRACE) {
@@ -121,15 +123,12 @@ if (!$auth_prihlasen &&
$stmt->execute([':selector' => $cookie_selector]); $stmt->execute([':selector' => $cookie_selector]);
$zaznam = $stmt->fetch(); $zaznam = $stmt->fetch();
// Příznak, zda je cookie platná
$cookie_ok = false; $cookie_ok = false;
if ($zaznam) { if ($zaznam) {
// Zkontrolujeme, zda token ještě nevypršel // Zkontrolujeme, zda token ještě nevypršel
$expiruje_timestamp = strtotime($zaznam['expiruje']); if (time() < strtotime($zaznam['expiruje'])) {
if (time() < $expiruje_timestamp) {
// Ověříme tajný token pomocí password_verify(). // Ověříme tajný token pomocí password_verify().
// Tato funkce záměrně trvá stejně dlouho bez ohledu // Tato funkce záměrně trvá stejně dlouho bez ohledu
@@ -143,7 +142,7 @@ if (!$auth_prihlasen &&
if ($cookie_ok) { if ($cookie_ok) {
// Cookie je platná obnovíme session // 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_regenerate_id(true);
$_SESSION['uzivatel_id'] = $zaznam['uzivatel_id']; $_SESSION['uzivatel_id'] = $zaznam['uzivatel_id'];
@@ -151,6 +150,11 @@ if (!$auth_prihlasen &&
$_SESSION['admin'] = (bool) $zaznam['admin']; $_SESSION['admin'] = (bool) $zaznam['admin'];
$_SESSION['posledni_aktivita'] = time(); $_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_prihlasen = true;
$auth_uzivatel = [ $auth_uzivatel = [
'id' => $zaznam['uzivatel_id'], 'id' => $zaznam['uzivatel_id'],
@@ -178,18 +182,17 @@ if (!$auth_prihlasen &&
'path' => '/', 'path' => '/',
'httponly' => true, 'httponly' => true,
'samesite' => 'Strict', 'samesite' => 'Strict',
// 'secure' => true, // odkomentuj pokud web běží na HTTPS // 'secure' => true,
]); ]);
setcookie('auth_token', $cookie_token, [ setcookie('auth_token', $cookie_token, [
'expires' => $nova_expirace, 'expires' => $nova_expirace,
'path' => '/', 'path' => '/',
'httponly' => true, 'httponly' => true,
'samesite' => 'Strict', 'samesite' => 'Strict',
// 'secure' => true, // odkomentuj pokud web běží na HTTPS // 'secure' => true,
]); ]);
// Smažeme staré (expirované) tokeny z DB // Smažeme staré (expirované) tokeny z DB příležitostně
// Děláme to zde příležitostně, aby se DB neplnila starými záznamy
$stmt3 = $pdo->prepare(" $stmt3 = $pdo->prepare("
DELETE FROM `" . DB_TABULKA_TOKENY . "` DELETE FROM `" . DB_TABULKA_TOKENY . "`
WHERE `expiruje` < :ted WHERE `expiruje` < :ted
@@ -198,8 +201,7 @@ if (!$auth_prihlasen &&
} else { } else {
// Cookie je neplatná nebo expirovaná smažeme ji z prohlížeče // Cookie je neplatná nebo expirovaná smažeme ji
// i případný záznam z DB (pokud selector existoval)
if ($zaznam) { if ($zaznam) {
$stmt4 = $pdo->prepare(" $stmt4 = $pdo->prepare("
DELETE FROM `" . DB_TABULKA_TOKENY . "` DELETE FROM `" . DB_TABULKA_TOKENY . "`
@@ -208,7 +210,6 @@ if (!$auth_prihlasen &&
$stmt4->execute([':id' => $zaznam['token_id']]); $stmt4->execute([':id' => $zaznam['token_id']]);
} }
// Smažeme cookies nastavením expirace do minulosti
setcookie('auth_selector', '', [ setcookie('auth_selector', '', [
'expires' => time() - 3600, 'expires' => time() - 3600,
'path' => '/', 'path' => '/',
@@ -230,18 +231,31 @@ if (!$auth_prihlasen &&
if (!$auth_prihlasen && VYZADOVAT_PRIHLASENI) { if (!$auth_prihlasen && VYZADOVAT_PRIHLASENI) {
// Uložíme URL aktuální stránky, aby se uživatel mohl po // Uložíme URL aktuální stránky pro přesměrování po přihlášení
// přihlášení vrátit tam, kde byl
$aktualni_url = $_SERVER['REQUEST_URI'] ?? ''; $aktualni_url = $_SERVER['REQUEST_URI'] ?? '';
if (!empty($aktualni_url)) { if (!empty($aktualni_url)) {
$_SESSION['redirect_po_prihlaseni'] = $aktualni_url; $_SESSION['redirect_po_prihlaseni'] = $aktualni_url;
} }
// Přesměujeme na přihlašovací stránku
header('Location: ' . AUTH_LOGIN_URL); header('Location: ' . AUTH_LOGIN_URL);
exit; 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 =
'<form method="POST" action="' . htmlspecialchars(AUTH_LOGOUT_URL) . '">'
. '<input type="hidden" name="csrf_token" value="'
. htmlspecialchars($_SESSION['csrf_token'] ?? '') . '">'
. '<button type="submit">Odhlásit se</button>'
. '</form>';
} }
+3
View File
@@ -50,6 +50,9 @@ define('PROJEKT_URL', 'https://example.com');
// Cesta k přihlašovací stránce (relativní od kořene projektu) // Cesta k přihlašovací stránce (relativní od kořene projektu)
define('AUTH_LOGIN_URL', '/auth/login.php'); 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í // Cesta k hlavní stránce po přihlášení
define('AUTH_REDIRECT_PO_PRIHLASENI', '/index.php'); define('AUTH_REDIRECT_PO_PRIHLASENI', '/index.php');