Un sistema di doppia autenticazione permette di aggiungere un livello di verifica sull'identità di un utente che desidera connettersi a una piattaforma o un'applicazione. Può essere visto come un onere dagli utenti perché richiede un passaggio aggiuntivo per accedere al contenuto desiderato, ma in alcuni casi è essenziale per garantire la sicurezza dei dati degli utenti. La doppia autenticazione rende anche più difficile l'automazione della connessione da parte di un robot, riducendo le possibilità di spam e frodi. Considerata come un metodo di autenticazione forte, la doppia autenticazione obbliga i tuoi utenti a fornire due prove di identità distinte. Questa metodo di autenticazione la si incontra molto spesso, senza nemmeno rendersene conto, con il pagamento tramite carta di credito. Infatti, pagare con la tua carta di credito inserendo il tuo codice segreto è una forma di doppia autenticazione, la prima prova essendo il possesso della carta di credito e la seconda, il codice segreto.
Ci fu un tempo in cui la maggior parte delle autenticazioni a due fattori (A2F) venivano effettuate via email. Autenticarsi via email può essere fastidioso per l'utente: dover aprire la propria casella di posta, aspettare che l'email arrivi, aprirla, quindi copiare e incollare il codice o cliccare su un link può scoraggiarne più di uno. Inoltre, una casella di posta può essere aperta contemporaneamente su una moltitudine di dispositivi diversi, aumentando il numero di vettori di intrusione possibili.
Come avrai sicuramente intuito dal titolo di questo articolo, vedremo come implementare un sistema di A2F utilizzando gli SMS. Il principio è che l'utente conferma la sua autenticazione inserendo un codice che riceve via SMS, chiamato One Time Password (OTP) . Questo mezzo di doppia autenticazione è più user friendly, soprattutto con la possibilità aggiunta dalla versione di iOS 12 di riempire automaticamente un campo con il codice ricevuto via SMS.
Nel seguito di questo articolo, vedremo come possiamo implementare una doppia autenticazione via SMS su un'applicazione in
React Native.
Flow
Al fine di integrare questo sistema di doppia autenticazione, concentriamoci prima sulla sequenza degli eventi.
Sulla nostra applicazione, quando un utente cercherà di connettersi, genereremo un OTP e lo salveremo in un database indicando una data di scadenza. Utilizzando un'API, invieremo quindi questo codice via SMS all'utente, che potrà poi inserirlo per completare l'autenticazione.

Schema degli scambi tra il frontend, il backend e l'API SMS
Prerequisiti
Nel seguito dell'articolo, supponiamo che esista un sistema di autenticazione con login e password, e spieghiamo come integrarlo con una verifica via SMS. Supponiamo anche che il numero di telefono degli utenti sia registrato nel database.
Vengono utilizzate le seguenti tecnologie:
Servizio di invio SMS
Per inviare gli SMS contenenti i codici di verifica, utilizzeremo il servizio
Twilio.
Twilio mette anche a disposizione
Verify, che è un'API all-in-one che permette di gestire l'invio di codici di verifica. In questo articolo, affinché il metodo presentato sia applicabile a qualsiasi servizio di invio SMS, utilizzeremo l'API classica di invio SMS di Twilio.
Per impostazione predefinita, un numero di spedizione viene mostrato al destinatario dell'SMS. Se desideri che il mittente sia visualizzato in formato alfanumerico, puoi consultare
questo articolo.

Sulla schermata a destra, il nome del mittente è in formato alfanumerico.
Creazione e invio dell'OTP
Una volta che l'utente ha inserito le sue credenziali e che l'applicazione ha verificato che fossero corrette, generiamo un OTP utilizzando la libreria
generate-sms-verification-code :
import * as phoneToken from 'generate-sms-verification-code'
const generateUserVerificationCode = () => {
return phoneToken(4);
}
Qui, viene generato un codice di 4 cifre.
Registriamo quindi il codice nel database con una data di scadenza:
await this.userRepository.update(user.userId, {
smsOTP: verificationCode,
otpExpirationDate: moment().add(5, 'm').toDate(),
});
Qui, il codice scade 5 minuti dopo la sua generazione.
Ora dobbiamo inviare il codice via SMS all'utente tramite Twilio. Per questo, è necessario avere il tuo Twilio Account SID e il tuo Twilio Auth Token, entrambi accessibili dalla tua console Twilio.
import * as twilio from 'twilio';
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);
async sendSMSToUser(user: User, body: string) {
const smsSent = await client.messages.create({
body,
to: user.phoneNumber,
from: process.env.TWILIO_PHONE_NUMBER,
});
return !!smsSent.sid;
}
Il codice qui sopra crea un client Twilio utilizzato per chiamare l'API di invio SMS con il metodo
create dell'oggetto
messages. Puoi trovare il codice completo della generazione e dell'invio del codice integrato in un sistema di autenticazione
qui.
Inserimento del codice di verifica
Ora che i tuoi utenti ricevono un codice quando cercano di connettersi, devono poterlo inserire nella tua applicazione per finalizzare l'autenticazione. Per questo utilizziamo la libreria
react-native-confirmation-code-field, che permette di creare campi di testo specificamente fatti per i codici.

Esempio di schermata codificata in React Native che permette di inserire un codice
Questa libreria ci lascia la possibilità di chiamare automaticamente una funzione quando il codice di verifica è stato completamente inserito (grazie alla proprietà onFulfill), così come di compilare automaticamente il codice inviato via SMS su iOS.
Nel nostro codice, abbiamo chiamato questa funzione onCodeInputFulfilled : invia il codice inserito dall'utente al backend, che restituisce una risposta al frontend indicando se il codice è valido o meno, con un errore se del caso. A seconda del risultato, l'utente viene reindirizzato a una schermata di successo, oppure gli viene mostrato un messaggio di errore.
const onCodeInputFulfilled = (value: string) => {
setIsProcessing(true);
submitVerificationCode(value, route.params.userId).then((res) => {
setIsProcessing(false);
if (res.success) {
navigation.navigate('SuccessScreen');
} else {
setErrorMessage(res.errorMessage);
}
});
};
Verifica del codice
Ecco il codice backend che permette di verificare se il codice inviato via SMS è valido:
@Post('/verifyCode')
async verifyUserCode(@Body() data, @Res() res) {
const verificationResult = await this.userService.verifyUserCode(
data.userId,
data.verificationCode,
);
res.status(HttpStatus.OK).send({
success: verificationResult.success,
errorMessage: verificationResult.errorMessage,
});
}}
Qui, la funzione verifyUserCode viene chiamata in seguito a una richiesta alla route /verifyCode. Chiama un'altra funzione verifyUserCode presente nel servizio NestJS che gestisce gli utenti, che abbiamo chiamato qui userService :
async verifyUserCode(userId: number, verificationCode: string) {
const retrievedUser = await this.userRepository.findOne({ userId });
if (verificationCode !== retrievedUser.smsOTP) {
return { success: false, errorMessage: 'Wrong verification code' };
} else if (moment().isAfter(retrievedUser.otpExpirationDate)) {
return { success: false, errorMessage: 'Verification code expired' };
} else {
return { success: true };
}
}
Questa funzione verifica che il codice inserito dall'utente e il codice generato e registrato nel database siano gli stessi. Verifica anche che il codice non sia scaduto.
Il risultato viene quindi inviato al frontend, con un errore se del caso.
Conclusione
Bravo! Hai appena imparato come integrare un sistema di doppia autenticazione che utilizza un codice di verifica inviato via SMS, con compilazione automatica del codice ricevuto su iOS. Abbiamo realizzato questo utilizzando React Native e NestJS, ma la logica presentata può essere applicata ad altre tecnologie.
Riassumiamo quanto abbiamo visto nell'articolo. Per integrare a un'autenticazione semplice un sistema di autenticazione a due fattori via SMS, è necessario prima di tutto assicurarsi di essere in possesso dei numeri di telefono dei tuoi utenti. Nel momento in cui l'utente preme il pulsante di connessione della tua applicazione, una verifica delle credenziali deve essere effettuata sul tuo backend. Se sono corrette, è necessario generare un OTP, salvarlo nel tuo database associandolo all'utente e inviarlo via SMS utilizzando un'API di invio SMS. Dal backend, quando hai la conferma dell'invio dell'SMS, puoi quindi inviare una risposta al frontend per confermare l'invio dell'SMS. Nel momento in cui l'applicazione riceve questa conferma, è necessario cambiare la schermata mostrata all'utente e lasciargli la possibilità di inserire questo OTP appena ricevuto. Quando l'utente ha finito di inserire il codice ricevuto, è necessario inviarlo tramite una richiesta al backend per validarlo. La validazione dell'OTP avviene confrontando quello memorizzato nel database prima dell'invio dell'SMS con quello inserito nell'applicazione (verificando anche la data di scadenza). Se il codice inserito è quello corretto, l'utente è autenticato e può essere reindirizzato alla schermata appropriata.
Per migliorare l'esperienza utente, si consiglia di mostrare un pulsante che permetta di rinviare il codice se non viene ricevuto. È preferibile renderlo inattivo una volta premuto per 15-30 secondi, per evitare numerosi invii che possono essere costosi e sovraccaricare il backend dell'applicazione.
Ecco il codice sorgente del sistema implementato:
Infine, ecco una GIF che illustra il percorso completo del sistema di autenticazione appena implementato:
Referenze