Inici de sessió: diferència entre les revisions
Es crea la pàgina amb «== Inici de sessió == == Connexió a la BD i inici de sessió (PHP) == == Formulari d'inici de sessió == Es mostra A més, en cas que no s’hagi registrat, tindrà un botó per registrar-se. A part, si no recorda de les seves credencials, tindrà un botó per poder recuperar la contrasenya. Per últim, també se li dona a l’usuari la oportunitat (sense obligar-lo) a autenticar-se amb el 2FA. == Inici de sessió manual == === Obtenció de les dades d'usua...». |
|||
| Línia 2: | Línia 2: | ||
== Connexió a la BD i inici de sessió (PHP) == | == Connexió a la BD i inici de sessió (PHP) == | ||
Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML | |||
session_start(); | |||
A més, hem de requerir el fitxer amb les funcions i una connexió a la BD. En aquest cas, si realitzem una autenticació errònia, haurem d'incrementar el número d'intents de login de la BD i per tant requerim la [[Connexions a la BD (A5.3)#Connexió d'escriptura|connexió d'escriptura]]. | |||
require 'funcions.php'; | |||
require './connexioBD/connexioRW.php'; | |||
== Comprovar si està autenticat == | |||
En cas que l'usuari està autenticat, el redirigirem directament a la seva pàgina privada. Per comprovar si l'usuari està autenticat farem servir la funció [[Funcions de la pràctica 5.3#esta autenticat|esta_autenticat]].<pre> | |||
// Redirigir si ja hi ha una sessió activa | |||
if (esta_autenticat()) { | |||
header('Location: privada.php'); | |||
exit; | |||
} | |||
</pre> | |||
== Formulari d'inici de sessió == | == Formulari d'inici de sessió == | ||
Al formulari es mostra dues entrades de text per introduir el nom d'usuari i la contrasenya. A més, en cas que no s’hagi registrat, tindrà un botó per registrar-se, i si no recorda de les seves credencials, tindrà un botó per poder recuperar la contrasenya. | |||
Per últim, també se li dona a l’usuari la oportunitat (sense obligar-lo) a autenticar-se amb | |||
També es mostra una casella de selecció perque l'aplicatiu el "recordi" | |||
Per últim, també se li dona a l’usuari la oportunitat (sense obligar-lo) a autenticar-se amb 2FA. | |||
El formulari es visualitzaria de la següent forma: | |||
[[Fitxer:FormulariIniciSessio.png|center|miniatura|559x559px]] | |||
== Inici de sessió manual == | == Inici de sessió manual == | ||
=== Obtenció de les dades d'usuari === | === Obtenció de les dades d'usuari del formulari i la BD === | ||
Un cop es respongui el formulari, obtindrem les dades del formulari i realitzarem una consulta per comprovar si el nom d'usuari realment existeix<pre> | |||
// Recuperem les dades del formulari | |||
$nom_usuari = trim($_POST['nom_usuari']); | |||
$contrasenya = $_POST['contrasenya']; | |||
$recordar = isset($_POST['recordar']); // Opció per crear o no galetes | |||
// Recuperem les dades de l'usuari amb el nom d'usuari especificat | |||
$stmt = $pdo->prepare("SELECT * FROM usuaris WHERE nom_usuari = ?"); | |||
$stmt->execute([$nom_usuari]); | |||
$usuari = $stmt->fetch(); | |||
// Verifiquem que l'usuari existeixi | |||
if ($usuari) { | |||
</pre> | |||
=== Comprovació d'usuari bloquejat === | === Comprovació d'usuari bloquejat === | ||
En cas que existeixi, primerament comprovarem si el compte està bloquejat. Per això comprovarem: | |||
* Que el nombre d’intents d’inici de sessió que s’ha enregistrat a la BD sigui major o igual a $max_intents, en aquest cas 3 intents | |||
* Si l’últim intent d’inici de sessió s’ha produit fa menys de $bloqueig_minuts, en aquest cas 2 minuts | |||
Si es cumpleixen els 2 requisits, el compte estarà bloquejat.<pre> | |||
// Comprovar si hi ha bloqueig | |||
if ($usuari['intents_login'] >= $max_intents | |||
&& strtotime($usuari['ultim_intent']) > strtotime("-$bloqueig_minuts minutes")) { | |||
</pre>Per fer el càlcul de les dates fem servir la funció interna de PHP strtotime(), la qual retorna la data introduida en temps UNIX (nº de segons des de 1/1/1970). | |||
strtotime($usuari['ultim_intent']) retorna el número de segons que han passat del 1/1/1970 a la data especificada (o dit d'una altra manera, quans segons han passat des de l’1/1/1970 fins el 10/1/2026 a les 15:00) | |||
strtotime("-$bloqueig_minuts minutes") retorna el número de segons que han passat des de l’1/1/1970 fa $bloqueig_minuts minuts (o dit d'una altra manera, quans segons han passat des de l’1/1/1970 fa 2 minuts) | |||
Així, tenim la mateixa “base temporal” amb la que fer càlculs | |||
En cas que el compte estigui bloquejat, mostrarem a l’usuari el temps que queda per desbloquejar-lo. | |||
Per això: | |||
# Calculem el temps (l’hora) UNIX de l’últim intent | |||
## Exemple (Exemple: 15:00 emmagatzemat en format UNIX) | |||
# Calculem el temps (l’hora) UNIX per que s’acabi el bloqueig | |||
## Agafem el temps de l’últim intent i li sumem X minuts en segons, en aquest cas 2 minuts per 60 segons | |||
## Exemple: (Exemple: 15:02, emmagatzemat en format UNIX) | |||
# Calculem els segons restants | |||
## Agafem el temps (hora) perquè s’acabi el bloqueig i restem a l’hora actual | |||
## Exemple: 15:02 - 15:01 = 00:01 (60 segons) | |||
# Convertim els segons restants a minuts i segons | |||
## 80 segons = 1 minut i 20 segons | |||
# Mostrem els minuts i segons restants | |||
<pre> | |||
// Calcular temps restant | |||
$ultim_intent_ts = strtotime($usuari['ultim_intent']); //Calculem el temps (l’hora) UNIX de l’últim intent | |||
$final_bloqueig_ts = $ultim_intent_ts + ($bloqueig_minuts * 60); //Calculem el temps (l’hora) UNIX per que s’acabi el bloqueig | |||
$segons_restants = $final_bloqueig_ts - time(); // Calculem els segons restants. Agafem el temps (hora) perquè s’acabi el bloqueig i restem a l’hora actual | |||
$minuts_restants = floor($segons_restants / 60); // Convertim els segons restants a minuts | |||
$segons_restants = $segons_restants % 60; // Recuperem els segons restants després de calcular les hores | |||
$error = "Compte bloquejat temporalment. Torna-ho a provar en {$minuts_restants} minuts i {$segons_restants} segons."; | |||
</pre>Per tant el fluxe del codi seria el següent: | |||
# L’usuari s’equivoca 3 vegades | |||
# Intenta accedir una 4ta, no pot (3 intents_login, 3 segons últim intent) | |||
# Espera 2 minuts (3 intents_login, 2 minuts últim intent, pot accedir) | |||
# Es torna a equivocar una 5na vegada (3 intents_login, 3 segons últim intent) | |||
# Torna a esperar 2 minuts | |||
# Accedeix correctament | |||
=== Comprovació de contrasenya === | === Comprovació de contrasenya === | ||
Un cop verificat que l'usuari no està bloquejat, comprovarem que la contrasenya sigui correcta amb la funció [[Funcions de la pràctica 5.3#verificar contrasenya|verificar_contrasenya]].<pre> | |||
if (verificar_contrasenya($contrasenya, $usuari['contrasenya'])) { | |||
</pre>En cas que la contrasenya sigui errònia, augmentarem en 1 els número d'intents d'autenticació, registrarem una acció a la taula activitat de nom "error-login" i registrarem un missatge d'error<pre> | |||
// Si la contrasenya és incorrecte, sumem un intent de login | |||
$stmt = $pdo->prepare("UPDATE usuaris SET intents_login = intents_login + 1, ultim_intent = NOW() WHERE id = ?"); | |||
$stmt->execute([$usuari['id']]); | |||
// Registrar intent fallit | |||
registrar_activitat($pdo, $usuari['id'], 'error-login'); | |||
$error = "Usuari o contrasenya incorrecte"; | |||
</pre> | |||
=== Inici de sessió === | === Inici de sessió === | ||
Si la contrasenya és correcte, actualitzarem el nombre d’intents de login a 0<pre> | |||
// Login correcte, resetajer intents | |||
$stmt = $pdo->prepare("UPDATE usuaris SET intents_login = 0, ultim_intent = NULL WHERE id = ?"); | |||
$stmt->execute([$usuari['id']]); | |||
</pre>Seguidament, regenerarem la ID de sessió per evitar atacs de sessió fixada<pre> | |||
session_regenerate_id(true); // Protecció session fixation | |||
</pre>Per acabar creant un vector de nom “usuari” dins de la sessió amb els següents vectors: | |||
* ID de l’usuari dins la BD | |||
* Nom d’usuari | |||
* Nom complet | |||
* Rol, per definir si és administrador o no i quin tipus | |||
* Autenticat, per definir que està autenticat | |||
<pre> | |||
$_SESSION['usuari'] = [ // Iniciem sessió a l'usuari indicant | |||
'id' => $usuari['id'], // El seu ID a la BD | |||
'nom_usuari' => $usuari['nom_usuari'], // El nom d'usuari | |||
'nom_complet' => $usuari['nom_complet'], // El nom complet | |||
'rol' => $usuari['rol'], // El seu rol (usuari, admin) | |||
'autenticat' => true // Definim que està autenticat | |||
]; | |||
</pre>Un cop autenticat, registrarem una acció a la taula activitat de nom "login" i redirigirem l'usuari a la seva pàgina privada<pre> | |||
// Registrem l'acció "login" | |||
registrar_activitat($pdo, $usuari['id'], 'login'); | |||
header('Location: privada.php'); | |||
exit; | |||
</pre> | |||
=== "Recordar-me" === | === "Recordar-me" === | ||
En cas que l'usuari hagi decidit que l'aplicació el recordi, generarem un token únic que ens servirà per identificar la seva identitat posteriorment en l'inici de sessió amb cookies<pre> | |||
// Generar un token únic i desar-lo a la BD | |||
$token = bin2hex(random_bytes(16)); | |||
</pre>Aquest token, juntament amb la ID de l'usuari les guardarem en galetes<pre> | |||
setcookie('recordar_id', $usuari['id'], time() + 30*24*60*60, '/'); // Recordem la ID de l'usuari | |||
setcookie('recordar_token', $token, time() + 30*24*60*60, '/'); // Recordem el token desat a la BD | |||
</pre>I per últim, desarem el token únic dins la BD en el registre de l'usuari<pre> | |||
$stmt = $pdo->prepare("UPDATE usuaris SET token_recordar = ? WHERE id = ?"); | |||
$stmt->execute([$token, $usuari['id']]); | |||
</pre> | |||
== Inici de sessió mitjançant cookies == | == Inici de sessió mitjançant cookies == | ||
Revisió del 22:37, 10 gen 2026
Inici de sessió
Connexió a la BD i inici de sessió (PHP)
Sempre que es treballa amb sessions, el primer que hem de fer és iniciar-la abans d'escriure el codi HTML
session_start();
A més, hem de requerir el fitxer amb les funcions i una connexió a la BD. En aquest cas, si realitzem una autenticació errònia, haurem d'incrementar el número d'intents de login de la BD i per tant requerim la connexió d'escriptura.
require 'funcions.php'; require './connexioBD/connexioRW.php';
Comprovar si està autenticat
En cas que l'usuari està autenticat, el redirigirem directament a la seva pàgina privada. Per comprovar si l'usuari està autenticat farem servir la funció esta_autenticat.
// Redirigir si ja hi ha una sessió activa
if (esta_autenticat()) {
header('Location: privada.php');
exit;
}
Formulari d'inici de sessió
Al formulari es mostra dues entrades de text per introduir el nom d'usuari i la contrasenya. A més, en cas que no s’hagi registrat, tindrà un botó per registrar-se, i si no recorda de les seves credencials, tindrà un botó per poder recuperar la contrasenya.
També es mostra una casella de selecció perque l'aplicatiu el "recordi"
Per últim, també se li dona a l’usuari la oportunitat (sense obligar-lo) a autenticar-se amb 2FA.
El formulari es visualitzaria de la següent forma:

Inici de sessió manual
Obtenció de les dades d'usuari del formulari i la BD
Un cop es respongui el formulari, obtindrem les dades del formulari i realitzarem una consulta per comprovar si el nom d'usuari realment existeix
// Recuperem les dades del formulari
$nom_usuari = trim($_POST['nom_usuari']);
$contrasenya = $_POST['contrasenya'];
$recordar = isset($_POST['recordar']); // Opció per crear o no galetes
// Recuperem les dades de l'usuari amb el nom d'usuari especificat
$stmt = $pdo->prepare("SELECT * FROM usuaris WHERE nom_usuari = ?");
$stmt->execute([$nom_usuari]);
$usuari = $stmt->fetch();
// Verifiquem que l'usuari existeixi
if ($usuari) {
Comprovació d'usuari bloquejat
En cas que existeixi, primerament comprovarem si el compte està bloquejat. Per això comprovarem:
- Que el nombre d’intents d’inici de sessió que s’ha enregistrat a la BD sigui major o igual a $max_intents, en aquest cas 3 intents
- Si l’últim intent d’inici de sessió s’ha produit fa menys de $bloqueig_minuts, en aquest cas 2 minuts
Si es cumpleixen els 2 requisits, el compte estarà bloquejat.
// Comprovar si hi ha bloqueig
if ($usuari['intents_login'] >= $max_intents
&& strtotime($usuari['ultim_intent']) > strtotime("-$bloqueig_minuts minutes")) {
Per fer el càlcul de les dates fem servir la funció interna de PHP strtotime(), la qual retorna la data introduida en temps UNIX (nº de segons des de 1/1/1970).
strtotime($usuari['ultim_intent']) retorna el número de segons que han passat del 1/1/1970 a la data especificada (o dit d'una altra manera, quans segons han passat des de l’1/1/1970 fins el 10/1/2026 a les 15:00)
strtotime("-$bloqueig_minuts minutes") retorna el número de segons que han passat des de l’1/1/1970 fa $bloqueig_minuts minuts (o dit d'una altra manera, quans segons han passat des de l’1/1/1970 fa 2 minuts)
Així, tenim la mateixa “base temporal” amb la que fer càlculs
En cas que el compte estigui bloquejat, mostrarem a l’usuari el temps que queda per desbloquejar-lo.
Per això:
- Calculem el temps (l’hora) UNIX de l’últim intent
- Exemple (Exemple: 15:00 emmagatzemat en format UNIX)
- Calculem el temps (l’hora) UNIX per que s’acabi el bloqueig
- Agafem el temps de l’últim intent i li sumem X minuts en segons, en aquest cas 2 minuts per 60 segons
- Exemple: (Exemple: 15:02, emmagatzemat en format UNIX)
- Calculem els segons restants
- Agafem el temps (hora) perquè s’acabi el bloqueig i restem a l’hora actual
- Exemple: 15:02 - 15:01 = 00:01 (60 segons)
- Convertim els segons restants a minuts i segons
- 80 segons = 1 minut i 20 segons
- Mostrem els minuts i segons restants
// Calcular temps restant
$ultim_intent_ts = strtotime($usuari['ultim_intent']); //Calculem el temps (l’hora) UNIX de l’últim intent
$final_bloqueig_ts = $ultim_intent_ts + ($bloqueig_minuts * 60); //Calculem el temps (l’hora) UNIX per que s’acabi el bloqueig
$segons_restants = $final_bloqueig_ts - time(); // Calculem els segons restants. Agafem el temps (hora) perquè s’acabi el bloqueig i restem a l’hora actual
$minuts_restants = floor($segons_restants / 60); // Convertim els segons restants a minuts
$segons_restants = $segons_restants % 60; // Recuperem els segons restants després de calcular les hores
$error = "Compte bloquejat temporalment. Torna-ho a provar en {$minuts_restants} minuts i {$segons_restants} segons.";
Per tant el fluxe del codi seria el següent:
- L’usuari s’equivoca 3 vegades
- Intenta accedir una 4ta, no pot (3 intents_login, 3 segons últim intent)
- Espera 2 minuts (3 intents_login, 2 minuts últim intent, pot accedir)
- Es torna a equivocar una 5na vegada (3 intents_login, 3 segons últim intent)
- Torna a esperar 2 minuts
- Accedeix correctament
Comprovació de contrasenya
Un cop verificat que l'usuari no està bloquejat, comprovarem que la contrasenya sigui correcta amb la funció verificar_contrasenya.
if (verificar_contrasenya($contrasenya, $usuari['contrasenya'])) {
En cas que la contrasenya sigui errònia, augmentarem en 1 els número d'intents d'autenticació, registrarem una acció a la taula activitat de nom "error-login" i registrarem un missatge d'error
// Si la contrasenya és incorrecte, sumem un intent de login
$stmt = $pdo->prepare("UPDATE usuaris SET intents_login = intents_login + 1, ultim_intent = NOW() WHERE id = ?"); $stmt->execute([$usuari['id']]);// Registrar intent fallit registrar_activitat($pdo, $usuari['id'], 'error-login'); $error = "Usuari o contrasenya incorrecte";
Inici de sessió
Si la contrasenya és correcte, actualitzarem el nombre d’intents de login a 0
// Login correcte, resetajer intents
$stmt = $pdo->prepare("UPDATE usuaris SET intents_login = 0, ultim_intent = NULL WHERE id = ?");
$stmt->execute([$usuari['id']]);
Seguidament, regenerarem la ID de sessió per evitar atacs de sessió fixada
session_regenerate_id(true); // Protecció session fixation
Per acabar creant un vector de nom “usuari” dins de la sessió amb els següents vectors:
- ID de l’usuari dins la BD
- Nom d’usuari
- Nom complet
- Rol, per definir si és administrador o no i quin tipus
- Autenticat, per definir que està autenticat
$_SESSION['usuari'] = [ // Iniciem sessió a l'usuari indicant
'id' => $usuari['id'], // El seu ID a la BD
'nom_usuari' => $usuari['nom_usuari'], // El nom d'usuari
'nom_complet' => $usuari['nom_complet'], // El nom complet
'rol' => $usuari['rol'], // El seu rol (usuari, admin)
'autenticat' => true // Definim que està autenticat
];
Un cop autenticat, registrarem una acció a la taula activitat de nom "login" i redirigirem l'usuari a la seva pàgina privada
// Registrem l'acció "login"
registrar_activitat($pdo, $usuari['id'], 'login'); header('Location: privada.php'); exit;
"Recordar-me"
En cas que l'usuari hagi decidit que l'aplicació el recordi, generarem un token únic que ens servirà per identificar la seva identitat posteriorment en l'inici de sessió amb cookies
// Generar un token únic i desar-lo a la BD $token = bin2hex(random_bytes(16));
Aquest token, juntament amb la ID de l'usuari les guardarem en galetes
setcookie('recordar_id', $usuari['id'], time() + 30*24*60*60, '/'); // Recordem la ID de l'usuari setcookie('recordar_token', $token, time() + 30*24*60*60, '/'); // Recordem el token desat a la BD
I per últim, desarem el token únic dins la BD en el registre de l'usuari
$stmt = $pdo->prepare("UPDATE usuaris SET token_recordar = ? WHERE id = ?"); $stmt->execute([$token, $usuari['id']]);