In questo capitolo vedremo come estendere la nostra implementazione dell'autenticazione a due fattori aggiungendo l'invio di SMS.
L'API REST di Clickatell
Per inviare gli SMS useremo le API REST di Clickatell. Dopo aver creato un account sul sito, dovremo generare una nuova API REST e ottenere il nostro token di autenticazione.
Quindi possiamo aggiungere una nuova variabile d'ambiente al file .env
di Laravel.
CLICKATELL_API_TOKEN=token
Questa variabile memorizza il token di autenticazione. Prima di poterlo usare nella nostra applicazione dobbiamo assicurarci di effettuare il refresh della cache delle impostazioni di configurazione.
php artisan config:clear
Se analizziamo con attenzione la documentazione delle API, noteremo che per i nostri scopi non è necessario installare una nuova dipendenza, abbiamo bisogno invece di un client HTTP che effettui la richiesta POST
in JSON e restituisca il risultato dell'operazione.
Fortunatamente Laravel dispone della classe Http
che è stata progettata appunto per operare con le API REST.
Un requisito da soddisfare per inviare con successo un SMS è quello di aggiungere il prefisso internazionale (39
nel caso dell'Italia) prima del numero completo di cellulare. Il numero così composto va inserito in un array anche se stiamo inviando un SMS ad un singolo utente.
I dati verrano inviati come corpo JSON della richiesta POST
. Un altro requisito fondamentale è quello di aggiungere alcuni header HTTP alla nostra richiesta, tra cui quello più importante è l'header Authorization
che conterrà il token di autenticazione delle API.
Possiamo quindi creare il seguente metodo di utility all'interno del nostro controller.
protected function sendSMS($to, $message)
{
$api_endpoint = 'https://api.clickatell.com/rest/message';
$api_token = env('CLICKATELL_API_TOKEN');
$recipient = '39' . $to;
$response = Http::withHeaders([
'X-Version' => '1',
'Accept' => 'application/json',
'Authorization' => 'bearer ' . $api_token
])->post($api_endpoint, [
'text' => $message,
'to' => [$recipient]
]);
return $response->successful();
}
Il metodo usa l'endpoint delle API dedicato all'invio di SMS. Reperiamo il nostro token di autenticazione dalla configurazione usando l'utility env()
di Laravel.
Quindi impostiamo gli header della richiesta HTTP POST
usando il metodo withHeaders()
della classe Http
. Il numero del destinatario va inserito sempre in un array, anche se si tratta di un solo numero. Se omettiamo l'array la richiesta verrà ignorata e non risulterà neanche nel log delle richieste nella dashboard utente su Clickatell.
Il metodo successful()
esegue una verifica sul codice di stato HTTP restituito dalle API REST. In caso di avvenuto invio le API di Clickatell restituiscono 202
come codice di stato coerentemente con lo standard REST. Tale metodo effettua appunto questa verifica booleana.
Ora possiamo modificare il metodo del controller che gestisce l'invio del codice di autenticazione.
protected function accessCode($customer)
{
$digits = '0123456789';
$rand_str = str_shuffle($digits);
$code = substr($rand_str, 0, 4);
$accessCode = new AccessCode([
'code' => $code,
'customer_id' => $customer->id
]);
$accessCode->save();
$msg = 'Your access code is: ' . $code;
$this->sendSMS($customer->mobile, $msg);
}
La procedura è identica a quella vista nel capitolo precedente, in questo caso l'unica differenza è che il codice di autenticazione viene inviato tramite SMS invece che per e-mail.
Gestione delle eccezioni
Un potenziale problema con tale soluzione è che inviamo l'SMS "al buio", nel senso che dovremo verificare se il metodo sendSMS()
restituisce true
o false
.
Cosa fare nel caso di un errore nelle API? A livello di user experience dovremmo sempre informare l'utente del problema che stiamo riscontrando e fornire nel form di autenticazione una action che permetta all'utente di reinviare un nuovo codice di autenticazione.
Se il problema è momentaneo, solitamente il codice verrà inviato al secondo tentativo. Ma se il problema è persistente, ossia se le API del servizio SMS che stiamo utilizzando sono sovraccariche o del tutto offline, l'utente non riuscirà ad effettuare l'accesso.
Una soluzione molto usata è quella di far scaricare all'utente un file con i codici di backup da utilizzare in casi come questo. Questa operazione andrebbe sempre fatta quando l'utente attiva l'autenticazione a due fattori nel suo account.
Lato server i codici andrebbero salvati nel database e collegati all'account dell'utente. In questo modo se le API hanno un problema l'utente riuscirà comunque ad effettuare il login.