La maggior parte dei siti web offre un sistema di autenticazione degli utenti, allo scopo di offrire servizi ed informazioni personalizzate su base utente. Per implementare un buon sistema ti autenticazione su un sito web occorre sviluppare alcune funzionalità di base, che sono

  • Protezione delle risorse che si occupano dell'autenticazione (o contengono i parametri che governano il processo di autenticazione), che non devono essere pubblicamente raggiungibili
  • Offrire un set di pagine per gestire l'autenticazione, in particolare: login, logout, benvenuto ed errore: quest'ultima è la pagina che viene caricata se l'utente inserisce dei dati errati, quindi dovrebbe rimandare alla pagina di login
  • Riconoscere gli utenti in modo sicuro, memorizzando le password nel database
  • Inserire il controllo dell'avvenuta autenticazione in ogni pagina del sito (tranne quelle pubbliche)
  • Permettere all'utente di spuntare la casella ricordami per evitare di inserire username e password ogni volta che torna sul nostro sito

Abbiamo già visto come soddisfare questi requisiti nell'articolo Autenticare gli utenti in PHP, ad eccezione della funzionalità “ricordami”. Oggi vedremo un modo di ricordare gli utenti in modo semplice ed efficace, rimanendo sempre dell'ambito del PHP. Cercheremo anche di discutere e motivare le scelte che ci porteranno alla soluzione finale.

Il problema

Assumendo di autenticare gli utenti come nell'esempio già visto, ad un certo punto la nostra pagina di autenticazione dovrebbe contenere un codice simile a quello qui sotto

if ($row['login']) {

$_SESSION['id'] = $row['codice'] ;

$_SESSION['rememberMe'] = $_POST['rememberMe'] ;

ecc...

dove stiamo considerando il caso in cui la casellina “ricordami” è un normalissimo input di una form HTML, che l'utente ha inviato mediante una richiesta HTTP POST. La pagina di login dovrebbe quindi contenere una riga come questa

<input name="rememberMe" id="rememberMe" type="checkbox"

checked="checked" value="1"/>

Fin qui sembra andare tutto liscio. L'utente può spuntare o non spuntare la casella “ricordami”, e noi ci occupiamo di memorizzare la sua scelta nella variabile di sessione omonima. C'è però un problema: se la sessione HTTP viene configurata per restare la stessa anche quando l'utente chiude il browser, al prossimo collegamento (con lo stesso ID di sessione) noi potremmo pensare di controllare la variabile $_SESSION['rememberMe'] per capire se dobbiamo riconoscere l'utente o no. Se questa variabile è off, ovvero l'utente non voleva essere ricordato, dobbiamo accertarci di distruggere la sessione e dirigere l'utente verso la pagina di login. In altre parole potremmo pensare di inserire il controllo

if ($_SESSION['id'] && !$_SESSION['rememberMe']) {

$_SESSION = array();

session_destroy();

}

Ma questo è sbagliato! Un controllo del genere distruggerà la sessione tutte le volte che un utente decide di effettuare il login senza spuntare la casella “ricordami”. Il codice qui sopra rende obbligatorio usare la funzione "ricordami" per potersi autenticare...

La soluzione

Quello che ci serve è uno stratagemma per distinguere tra quattro possibili situazioni:

  • Utente loggato nella sessione CORRENTE senza opzione “ricordami”
  • Utente loggato nella sessione PRECEDENTE senza opzione “ricordami”
  • Utente loggato nella sessione CORRENTE con opzione “ricordami”
  • Utente loggato nella sessione PRECEDENTE con opzione “ricordami”

Adesso che abbiamo ben schematizzato i possibili scenari d'uso, diventa più facile capire quando dobbiamo inserire il controllo per resettare la sessione HTTP. Dei quattro casi qui sopra, quello incriminato è il secondo: l'utente si era loggato la volta scorsa, senza spuntare la casellina “ricordami”, quindi si aspetta di non essere riconosciuto. Per identificare questa situazione aggiungiamo un cookie “provvisorio” al momento dell'autenticazione. Il nostro codice di login diventa

 if ($row['login']) {

$_SESSION['id'] = $row['codice'] ;

$_SESSION['rememberMe'] = $_POST['rememberMe'] ;

setcookie('my_remember',$_POST['rememberMe'],0, "/");

ecc...

Si tratta di un cookie che “morirà” quando l'utente chiuderà il browser, e serve unicamente a farci distinguere il primo controllo da quelli successivi, senza andare ad accorciare la vita della sessione HTTP, che in questo modo può rimanere la stessa collegamento dopo collegamento.

Il controllo sulla necessità di distruggere la sessione sarà qualcosa del genere:

 if ($_SESSION['id'] && !isset($_COOKIE['my_remember'])

&& !$_SESSION['rememberMe']) {

$_SESSION = array();

session_destroy();

}

in questo modo distruggeremo la sessione solamente se questa è un retaggio del collegamento precedente (ho ancora una variabile $_SESSION['id']), l'utente non si è appena autenticato (non abbiamo il cookie my_remember) e la volta precedente l'utente non ha scelto l'opzione ricordami (la variabile $_SESSION['rememberMe']) è settata a zero).

La scelta di usare il cookie per risolvere il problema non è l'unica possibile, ma è semplice ed efficace: provare per credere!