
Teilen Sie:
Hui Jing ist Developer Advocate bei Nexmo. Sie hat eine übermäßige Liebe zu CSS und Typografie und ist allgemein leidenschaftlich über alle Dinge im Web.
Hinzufügen der Zwei-Faktor-Authentifizierung mit Node.js und Koa.js
Lesedauer: 13 Minuten
Die Zwei-Faktor-Authentifizierung (2FA) verdankt ihren Namen der Tatsache, dass Sie zwei Dinge benötigen, um Ihre Identität zu verifizieren. Etwas, das Sie wissen, z. B. ein Passwort, und etwas, das Sie haben, z. B. den Verifizierungscode von Ihrem Mobilgerät oder einen physischen Token.
Das Hinzufügen von 2FA zu Ihrer Anwendung muss keine schwierige Aufgabe sein. In diesem Tutorial erfahren Sie, wie Sie mit Hilfe der Vonage Verify API 2FA für Ihre Web-Applikationen und -Services implementieren, um eine zusätzliche Sicherheitsebene zu schaffen. Wir werden eine einfache Koa.js-Anwendung erstellen, um zu verstehen, wie der zugrunde liegende Mechanismus funktioniert. Dadurch wird es einfacher zu sehen, wie dies in Ihre eigenen bestehenden Projekte passt, auch wenn Sie Koa.js nicht verwenden.
In diesem Tutorial wird gezeigt, wie man ein Verifizierungs-Token-System mit der Vonage Verify API und Koa.js implementiert. Wir haben ein ähnliches Node.js-Tutorial mit Express.js - Sie können es hier finden.
Sie beginnen mit einer Anmeldeseite, auf der Sie Ihre Benutzer nach einer Handynummer fragen. Nach der Eingabe wird er aufgefordert, einen Verifizierungscode einzugeben, der per SMS an seine Mobiltelefonnummer geschickt wird. Sobald das erledigt ist, kann der Nutzer auf die Anwendung zugreifen.
Voraussetzungen
Ein grundlegendes Verständnis von Javascript
Node.js auf Ihrem Rechner installiert
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.
Sobald Sie ein Vonage API-Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf der Seite Vonage-API-Dashboard.
Dieses Tutorial führt Sie von Anfang an durch den Prozess. Wenn Sie den fertigen Code sehen möchten, können Sie das Git-Repository für dieses Projekt klonen. Wir haben auch eine Glitch-Version, die ein noch ausgefalleneres Design hat, und Sie können remixen remixen. Beachten Sie, dass es bei der Glitch-Implementierung leichte Unterschiede gibt, um der Art und Weise, wie Projekte auf der Plattform gehostet werden, Rechnung zu tragen.
Glitch version of demo
Ein Koa.js-Projekt von Grund auf neu beginnen
Erstellen Sie einen Projektordner auf Ihrem lokalen Rechner und führen Sie dann den folgenden Befehl aus, um ein neues Node.js-Projekt einzurichten.
Dies löst eine Reihe von Eingabeaufforderungen aus, die Ihre package.json Datei erstellt. Wenn Sie möchten, können Sie die Antworten leer lassen und die Standardwerte verwenden.
Configuring package.json
Als nächstes installieren Sie Koa.js. Beachten Sie, dass Koa für ES2015 und die Unterstützung von asynchronen Funktionen Node 7.6.0 oder höher benötigt.
Erstellen Sie eine server.js Datei in Ihrem Projektordner.
Fügen Sie den folgenden Code in Ihre neu erstellte Datei ein.
const Koa = require('koa')
const port = process.env.PORT || 3000
const app = new Koa()
app.use(async ctx => {
ctx.body = 'Hello Unicorn 🦄'
})
const listener = app.listen(port, function() {
console.log('Your app is listening on port ' + listener.address().port)
})
Führen Sie die server.js Datei aus.
Wenn Sie zu http://localhost:3000 in Ihrem Browser aufrufen, sollten Sie eine leere Seite mit dem Text "Hello Unicorn 🦄" sehen.
Check that server is running
Sie sollten auch Folgendes installieren dotenvinstallieren, das Ihnen erlaubt, Umgebungsvariablen, die in einer .env Datei gespeicherten Umgebungsvariablen in process.env.
Und nun können Sie die Datei .env Datei erstellen, die mindestens die folgenden Variablen enthalten sollte:
Um auf Umgebungsvariablen zugreifen zu können, müssen Sie sie anfordern, idealerweise am Anfang Ihrer server.js Datei.
require('dotenv').config()Wenn Sie sich noch nicht für einen Nexmo Account angemeldet haben haben, ist jetzt ein guter Zeitpunkt, dies zu tun. Sobald Sie sich im Dashboard angemeldet haben, sollten Ihre API-Anmeldedaten das erste sein, was Sie sehen. Achten Sie darauf, sowohl Ihren Schlüssel als auch Ihr Geheimnis in Anführungszeichen zu setzen.
Projektstruktur
Im Moment würde Ihr Projekt wahrscheinlich nur eine package.json, a server.js Datei und eine .env Datei. Lassen Sie uns die Projektstruktur so einrichten, dass Sie ein grundlegendes Frontend haben, mit dem die Benutzer interagieren können.
PROJECT_NAME/
|-- public/
| |-- client.js
| `-- style.css
|-- views/
| `-- index.html
|-- .env
|-- package.json
`-- server.jsIn diesem Fall müssen Sie einige Änderungen an der server.js Datei vornehmen, um die index.html Datei und die zugehörigen Assets zu liefern, anstatt nur eine Textzeile. Koa.js ist ein recht einfaches Framework, so dass alle zusätzlichen Funktionen für das Routing oder die Bereitstellung statischer Elemente separat installiert werden müssen. Hier ist die Liste der zusätzlichen Module und ihrer Verwendungen:
koa-staticfür die Bereitstellung statischer Inhaltekoa-bodyparserfür die Behandlung von Daten, die über POST-Anfragen gesendet werdenkoa-routerfür Routingkoa-viewszum Rendern von Vorlagen
Dieses Beispiel verwendet auch die Nunjucks um Vorlagendateien zu rendern. Die Vonage Verify API wird verwendet, um den Verifizierungscode per SMS auszulösen, daher müssen Sie auch die Vonage Node.js Client-Bibliothek installieren.
Bereitstellen von statischen Assets und HTML-Dateien
Damit die Anwendung statische Elemente wie Stylesheets und clientseitiges JavaScript aus dem Verzeichnis /public zu ermöglichen, können Sie Folgendes in die server.js Datei hinzufügen:
const serve = require('koa-static')
app.use(serve('./public'))Um HTML-Dateien aus dem Verzeichnis /views Ordner auszuliefern, können Sie die Funktion koa-viewsverwenden, die eine render() Funktion bietet. Die in diesem Beispiel verwendete Template-Engine ist Nunjucks, aber es steht Ihnen frei, die für Sie am besten geeignete Template-Engine zu wählen.
const views = require('koa-views')
app.use(views('./views', { map: { html: 'nunjucks' }}))Als nächstes müssen Sie einige grundlegende Routen für die Bereitstellung Ihrer Anwendungsseiten einrichten.
const Router = require('koa-router')
const router = new Router()
router.get('/', (ctx, next) => {
return ctx.render('./index')
})
app.use(router.routes()).use(router.allowedMethods())
Für dieses Beispiel werden Sie 3 Seiten benötigen, die index.html als Haupt-Landingpage, verify.html für die Eingabe des Verifizierungscodes durch die Benutzer und result.html um anzuzeigen, ob die Verifizierung erfolgreich war oder nicht.
Die Struktur des Webformulars ist recht einfach, und es steht Ihnen frei, es nach Belieben mit CSS zu verschönern.
<form method="post" action="verify">
<input name="phone" type="tel" placeholder="+6588888888">
<button>Get OTP</button>
</form>Dieses Formular wird die Benutzereingaben an die /verify und Sie können die Telefonnummer in der Eingabe verwenden, um die Anforderung des Verifizierungscodes auszulösen. Ein ähnliches Formular kann für die anderen 2 Routen verwendet werden für /check und /cancel verwendet werden.
<form method="post" action="check">
<input name="pin" placeholder="Enter PIN">
<input name="reqId" type="hidden" value="{{ reqId }}">
<button>Verify</button>
</form><form method="post" action="cancel">
<input name="reqId" type="hidden" value="{{ reqId }}">
<button class="inline">Cancel verification</button>
</form> Behandlung von Benutzereingaben
Für die Bearbeitung von Benutzereingaben über Webformulare benötigen Sie dann einige Routen zur Bearbeitung von POST Anfragen zu bearbeiten. Stellen Sie sicher, dass Sie bodyparser() vor jeder der Routen zu deklarieren.
const bodyParser = require('koa-bodyparser')
/* This should appear before any routes */
app.use(bodyParser())
router.post('/verify/', async (ctx, next) => {
const payload = await ctx.request.body
/* Function to trigger verification code here */
})
router.post('/check/', async (ctx, next) => {
const payload = await ctx.request.body
/* Function to check verification code here */
})
router.post('/cancel/', async (ctx, next) => {
const payload = await ctx.request.body
/* Function to cancel verification code here */
})
Nachdem Sie nun die Telefonnummer Ihres Benutzers erhalten haben, müssen Sie die Verify API verwenden, um einen PIN-Code an diesen zu senden. Initialisieren Sie eine neue Nexmo-Instanz mit Ihren Vonage-API-Anmeldedaten.
const Nexmo = require('nexmo');
const nexmo = new Nexmo({
apiKey: YOUR_API_KEY,
apiSecret: YOUR_API_SECRET
});Es gibt 3 Funktionen, um die wir uns kümmern müssen. Die erste ist die Auslösung des Verifizierungscodes mit der nexmo.verify.request() Funktion. Sie umfasst die Telefonnummer des Benutzers und eine Zeichenfolge für den Markennamen, der dem Benutzer als Absender angezeigt wird.
async function verify(number) {
return new Promise(function(resolve, reject) {
nexmo.verify.request({
number: number,
brand: process.env.NEXMO_BRAND_NAME
}, (err, result) => {
if (err) {
console.error(err)
reject(err)
} else {
resolve(result)
}
})
})
}
Sobald Ihr Benutzer den PIN-Code per SMS erhalten hat, muss er ihn an die nexmo.verify.check() Funktion eingeben, damit er verifiziert werden kann. Sie werden einen request_id Parameter. Diesen Wert erhält man, wenn der PIN-Code erfolgreich ausgelöst wurde. Es gibt eine Reihe von Möglichkeiten, die Anfrage-ID an die Funktion nexmo.verify.check() Funktion zu übergeben, und in diesem Beispiel wird ein verstecktes Feld in der Prüfung Formular.
async function check(reqId, code) {
return new Promise(function(resolve, reject) {
nexmo.verify.check({
request_id: reqId,
code: code
}, (err, result) => {
if (err) {
console.error(err)
reject(err)
} else {
resolve(result)
}
})
})
}
Die letzte Funktion gibt dem Benutzer die Möglichkeit, die Überprüfung abzubrechen, wenn er seine Meinung geändert hat. Sie verwendet die Funktion nexmo.verify.control() Funktion und erfordert wiederum die Anfrage-ID, die beim Auslösen des PIN-Codes generiert wird, sowie einen String-Wert von cancel.
async function cancel(reqId) {
return new Promise(function(resolve, reject) {
nexmo.verify.control({
request_id: reqId,
cmd: 'cancel'
}, (err, result) => {
if (err) {
console.error(err)
reject(err)
} else {
resolve(result)
}
})
})
}
Landing page for demo
Nun müssen Sie diese 3 Funktionen in den zuvor festgelegten Routen verwenden, wobei Sie zuerst mit der Funktion zum Auslösen des Verifizierungscodes beginnen.
router.post('/verify/', async (ctx, next) => {
const payload = await ctx.request.body
const phone = payload.phone
const result = await verify(phone)
const reqId = result.request_id
ctx.status = 200
return ctx.render('./verify', { reqId: reqId })
})
Die ctx.request.body wird in etwa so aussehen:
{
"phone": "+40987654321"
}Sie können diese Telefonnummer nehmen und sie an die verify() Funktion übergeben. Solange es sich um eine gültige Telefonnummer handelt, wird der Verifizierungscode abgefeuert und Sie erhalten eine Antwort, die ein request_id und status.
{
"request_id": "1bf002ecd1e94d8aa81ba7463b19f583",
"status": "0"
}Von dort aus können Sie die Anfrage-ID an das Frontend senden, wenn der Benutzer den Verifizierungscode eingibt.
The request_id is passed to the frontend
Wenn Ihr Benutzer die richtige PIN eingibt, müssen Sie sowohl die PIN als auch die Anfrage-ID in die check() Funktion eingeben.
router.post('/check/', async (ctx, next) => {
const payload = await ctx.request.body
const code = payload.pin
const reqId = payload.reqId
const result = await check(reqId, code)
const status = result.status
ctx.status = 200
return ctx.render('./result', { status: status })
})
Auch diese beiden Werte können über die Seite ctx.request.body und wenn die PIN als korrekt validiert wird, erhalten Sie eine Antwort, die wie folgt aussieht:
{
"request_id": "1bf002ecd1e94d8aa81ba7463b19f583",
"status": "0",
"event_id": "150000001AC57AB2",
"price": "0.10000000",
"currency": "EUR"
}Anhand des Statuscodes können Sie dann bestimmen, welche Meldung Sie dem Benutzer anzeigen möchten. In diesem Beispiel wird Nunjucks verwendet, so dass das Markup auf der Ergebnisseite etwa so aussehen könnte:
{% if status == 0 %}
<p>Code verified successfully. ¯\_(ツ)_/¯</p>
{% else %}
<p>Something went wrong… ಠ_ಠ</p>
<p>Please contact the administrator for more information.</p>
{% endif %}
Verification messages
Dies war eine gründliche Aufschlüsselung der einzelnen Teile des Codes, aber um einen Blick darauf zu werfen, wie die Anwendung in ihrer Gesamtheit aussieht, sollten Sie sich den Quellcode auf GitHub.
Zusätzliche Dinge, die zu beachten sind
Dieses Tutorial ist eine abgespeckte Version, die nur die für die Implementierung der Zwei-Faktor-Authentifizierung notwendigen Teile hervorhebt. Es gibt jedoch zahlreiche Dinge, die in einer tatsächlichen Anwendung beachtet werden müssen. Einer der wichtigsten Punkte ist die Fehlerbehandlung. Die Verify API gibt einen Statuswert von 0 für erfolgreiche Abfragen zurück, aber jeder andere Wert zeigt einen Fehler an.
Diese Fehler sollten behandelt werden, und die Benutzeroberfläche des Frontends sollte alle potenziellen Fehler, die eine erfolgreiche Überprüfung verhindern, widerspiegeln. Es könnte auch eine gute Idee sein, eine Art von Frontend-Validierung zu implementieren, oder sogar die Vonage Number Insight API zu nutzen, um sicherzustellen, dass nur gültige Numbers an die Verify API weitergeleitet werden.
Wie geht es weiter?
Wenn Sie mehr mit diesen APIs machen wollen, finden Sie hier einige Links, die Ihnen helfen könnten:
Dokumentation für die Verify API auf dem Entwicklerportal
Reihe von Anleitungen für verschiedene Vonage APIs
Wenn Sie uns brauchen, versuchen Sie den Vonage Entwickler-Community Slack-Kanal
Lassen Sie uns wissen, was Sie denken, indem Sie tweeten unter @VonageDev
