
Teilen Sie:
Michael ist ein polyglotter Software-Ingenieur, der sich dafür einsetzt, die Komplexität von Systemen zu reduzieren und sie berechenbarer zu machen. Er arbeitet mit einer Vielzahl von Sprachen und Tools und gibt sein technisches Fachwissen auf Benutzergruppen und Konferenzen in der ganzen Welt weiter. Im Alltag ist Michael ein ehemaliger Developer Advocate bei Vonage, wo er seine Zeit damit verbrachte, über alle Arten von Technologie zu lernen, zu lehren und zu schreiben.
2FA-Anmeldung mit Laravel und Nexmo
Dieser Beitrag erschien ursprünglich auf michaelheap.com vor Michael dem Nexmo Team!
Ich schrieb kürzlich über Bootstrapping von Laravel mit Benutzerauthentifizierung und wie einfach das ist (ernsthaft, es dauert weniger als 5 Minuten). Damit haben wir einen guten Ausgangspunkt für unsere Applications, aber dann stolperte ich über diesen Beitrag über die Integration der Zwei-Faktor-Authentifizierung mit Google Authenticator gestolpert und habe mir Gedanken über Nexmo Verify.
Ich habe kürzlich Verify in einen Chatbot integriert ohne Probleme integriert, und ich dachte, dass es eine nützliche Sache sein könnte, um sie in meinen Laravel-Login-Flow zu integrieren.
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.
Erfassen der Telefonnummer des Benutzers
Wir müssen die Telefonnummer des Benutzers erfassen - ohne sie können wir ihm keine Bestätigungsnachricht schicken. Wir könnten sie erfassen, nachdem sich der Benutzer registriert hat, aber ich habe beschlossen, sie stattdessen bei der Registrierung zu erfassen.
Als Erstes müssen wir die Tabelle users so ändern, dass ein Feld für die Speicherung der Telefonnummer des Benutzers vorhanden ist. Zu diesem Zweck erstellen wir eine neue Migration, um unsere users Tabelle:
Dadurch wird eine Datei im Ordner database/migrations Ordner mit dem Namen <current time>_add_users_phone_number.php. Öffnen Sie diese Datei und ersetzen Sie ihren Inhalt durch den folgenden Text:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddUsersPhoneNumber extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('phone_number');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('phone_number');
});
}
}Diese Migration fügt eine Spalte namens phone_number hinzu und löscht die Spalte, wenn sie zurückgesetzt wird. Wenden Sie sie jetzt an, indem Sie php artisan migrate in Ihrem Terminal ausführen.
Als Nächstes müssen wir eine Texteingabe zu unserem Registrierungsformular hinzufügen, damit der Benutzer seine Telefonnummer angeben kann. Bearbeiten Sie resources/views/auth/register.blade.php und fügen Sie den folgenden Text am Ende des Formulars kurz vor der Schaltfläche "Submit" ein:
<div class="form-group{{ $errors->has('phone_number') ? ' has-error' : '' }}">
<label for="name" class="col-md-4 control-label">Phone Number</label>
<div class="col-md-6">
<input id="name" type="tel" class="form-control" name="phone_number" value="{{ old('phone_number') }}" required autofocus>
@if ($errors->has('phone_number'))
<span class="help-block">
<strong>{{ $errors->first('phone_number') }}</strong>
</span>
@endif
</div>
</div>Wenn wir jetzt http://localhost:8000/register besuchen, sollten wir das Telefonnummernfeld unten in unserem Anmeldeformular sehen. Wir haben es fast geschafft, aber es fehlt noch ein wichtiger Teil - wir speichern die Nummer, die der Benutzer angibt, nicht in unserem neuen Feld in der Datenbank.
Laravel behält seine gesamte Logik für die Registrierung eines Benutzers in der app/Http/Controllers/Auth/RegisterController.php Datei. Öffnen Sie die Datei und werfen Sie einen Blick darauf - Sie sollten eine validator Methode und eine create Methode sehen. Wir müssen diese beiden ändern, um die Telefonnummer unseres Benutzers zu speichern.
Beginnen wir mit der validator Methode. Wir müssen einen neuen Eintrag für phone_number hinzufügen, um sicherzustellen, dass die angegebene Nummer gültig ist. Ich habe mich für recht strenge Validierungsregeln entschieden und verlange, dass die Nummer genau 12 Zeichen lang und für alle Benutzer eindeutig ist - Sie können auch weniger streng sein. Nachdem Sie eine Überprüfungsregel hinzugefügt haben, sollte Ihre validator Methode ähnlich wie die folgende aussehen:
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
'phone_number' =>; 'required|size:12|unique:users',
]);Sobald diese Daten die von uns festgelegten Validierungsregeln erfüllt haben, müssen wir sie in der Datenbank speichern. Zu diesem Zweck bearbeiten wir die create Methode und fügen eine Zeile hinzu, die unsere Telefonnummer speichert. Alle eingehenden Anfragedaten sind in der $data zur Verfügung, so dass es so einfach ist wie das Hinzufügen einer einzigen Zeile:
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'phone_number' =>; $data['phone_number']
]);
Wenn wir jetzt versuchen, einen Benutzer hinzuzufügen, wird es nicht wie erwartet funktionieren. Dies ist auf eine Sicherheitsfunktion in Laravel zurückzuführen, die eine massenhafte Zuweisung von Eigenschaften zu einer Klasse verhindert. Wir haben unsere Klasse nicht darüber informiert User Klasse nicht mitgeteilt, dass phone_number ein gültiges Feld ist, also wird sie unsere Anfrage, es zu speichern, zurückweisen. Um dieses Problem zu lösen, bearbeiten Sie app/User.php und fügen Sie phone_number zu dem $fillable Array:
protected $fillable = [
'name', 'email', 'password', 'phone_number'
];Nachdem Sie diese Änderung vorgenommen haben, können Sie einen Account auf der Seite registrieren und melden Sie sich bei unserer Anwendung an.
Hinzufügen von Nexmo Verify
Da wir nun die Telefonnummer des Benutzers haben, können wir mit der Implementierung unserer Verify-Logik beginnen. Laravel lässt die Login-Anfrage des Benutzers durch app/Http/Controllers/Auth/LoginController.php um herauszufinden, ob die angegebenen Anmeldeinformationen gültig sind oder nicht. Wenn die Anmeldedaten gültig sind, sucht Laravel dann nach einer authenticated Methode in der LoginController. Wenn die Methode existiert, wird die darin enthaltene Logik ausgeführt. Hier fügen wir unsere Logik für die Zwei-Faktor-Authentifizierung ein.
Öffnen Sie app/Http/Controllers/Auth/LoginController.php und fügen Sie Folgendes oben neben den anderen use Deklarationen:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Contracts\Auth\Authenticatable;Wir brauchen diese drei use Anweisungen, um einen Hinweis auf unsere authenticated Methode zu geben, die wir als nächstes hinzufügen sollten. Fügen Sie Folgendes in die LoginController Klasse hinzu:
public function authenticated(Request $request, Authenticatable $user)
{
Auth::logout();
$request->session()->put('verify:user:id', $user->id);
// @TODO: Send the Verify SMS here
return redirect('verify');
}
Dieser Code meldet den Benutzer wieder ab und speichert seine Benutzer-ID in der Sitzung, damit wir wissen, als welcher Benutzer er sich anzumelden versucht hat. Sobald die Verify-Anfrage abgeschlossen ist, verwenden wir diese ID, um den Benutzer automatisch wieder anzumelden.
Auslösen einer Verify-Anfrage
Sie haben vielleicht bemerkt, dass es ein @TODO um die Verify SMS Logik hinzuzufügen. Wir haben derzeit noch keine Möglichkeit, eine SMS über Nexmo zu versenden, also kümmern wir uns als nächstes darum. Zum Glück hat Nexmo ein Laravel-Paket das dies für uns sehr einfach macht. Wir folgen der README in diesem Projekt und installieren sowohl den Nexmo-Client als auch den Laravel-Dienstanbieter mit Composer:
Nach der Installation müssen wir Laravel mitteilen, dass unser Client existiert. Dazu müssen wir zwei Abschnitte in config/app.php um dies zu tun - providers und aliases.
Fügen Sie Folgendes hinzu providers:
Nexmo\Laravel\NexmoServiceProvider::classFügen Sie Folgendes hinzu aliases:
'Nexmo' => \Nexmo\Laravel\Facade\Nexmo::class
Schließlich müssen wir noch php artisan vendor:publish ausführen, um unsere Nexmo-Konfigurationsdatei zu erzeugen. Sobald wir diesen Befehl ausgeführt haben, können wir die Datei config/nexmo.php bearbeiten und unsere API-Anmeldedaten in api_key und api_secret. Wir können sie entweder direkt hier angeben, oder wir können die .env ähnlich wie bei der Datenbankkonfigurationsdatei. Ich werde die .env Datei verwenden, also habe ich die Datei config/nexmo.php so geändert, dass sie Folgendes enthält:
'api_key' => env('NEXMO_KEY', ''),
'api_secret' => env('NEXMO_SECRET', ''),
Dann in .envhabe ich zwei Einträge am Ende der Datei eingefügt - NEXMO_KEY und NEXMO_SECRET:
Nun, da der Nexmo-Client konfiguriert ist, können wir zurückgehen zu app/Http/Controllers/Auth/LoginController.php und unser Benachrichtigungssystem implementieren. Ersetzen Sie den @TODO Kommentar, den wir hinterlassen haben, durch den folgenden:
$verification = Nexmo::verify()->start([
'number' => $user->phone_number,
'brand' => 'Laravel Demo'
]);
$request->session()->put('verify:request_id', $verification->getRequestId());
Dadurch wird eine Verify-Anfrage über Nexmo an die Telefonnummer ausgelöst, die wir für diesen Benutzer gespeichert haben. Wir müssen auch use Nexmo; oben in der Datei hinzufügen, damit unsere Fassade verfügbar ist. Danach können Sie sich einloggen und eine Verify-Anfrage auslösen - aber tun Sie das noch nicht! Wir haben keine Möglichkeit für den Benutzer, seinen Verifizierungscode anzugeben, so dass Sie nicht in der Lage sein werden, Ihre Identität zu bestätigen.
Überprüfung des Antrags
Am Ende von LoginController::authenticated leiten wir den Benutzer zu einer /verify Url um. Es ist an der Zeit, diese Route bei Laravel zu registrieren und eine Implementierung dafür zu schreiben.
Öffnen Sie routes/web.php und fügen Sie den folgenden Text am Ende der Seite ein:
Route::get('/verify', 'VerifyController@show')->name('verify');
Route::post('/verify', 'VerifyController@verify')->name('verify');
Damit werden zwei Routen registriert (a GET und a POST an /verify), die wir verwenden werden, um den Code eines Benutzers zu verifizieren. Wir haben Laravel mitgeteilt, dass es die Routen show und verify Methoden auf der VerifyController für diese Anfragen aufrufen soll, also sollten wir den Controller generieren indem wir artisan:
php artisan make:controller VerifyControllerDadurch wird eine Datei unter app/Http/Controllers/VerifyController.php - Sie sollten deren Inhalt durch den folgenden Inhalt ersetzen:
<?php
namespace App\Http\Controllers;
use Auth;
use Nexmo;
use Illuminate\Http\Request;
class VerifyController extends Controller
{
public function show(Request $request) {
return view('verify');
}
public function verify(Request $request) {
return 'Not Implemented';
}
}Das reicht aus, um die Verify-Ansicht anzuzeigen, wenn jemand eine GET-Anfrage an /verify stellt. Noch einmal, diese Datei existiert noch nicht, also erstellen wir sie unter resources/views/verify.blade.php mit dem folgenden Inhalt:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Verify</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ route('verify') }}">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('code') ? ' has-error' : '' }}">
<label for="code" class="col-md-4 control-label">Code</label>
<div class="col-md-6">
<input id="code" type="number" class="form-control" name="code" value="{{ old('code') }}" required autofocus>
@if ($errors->has('code'))
<span class="help-block">
<strong>{{ $errors->first('code') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Verify Account
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsectionEs gibt eine Menge HTML, aber alles, was es tut, ist ein einziges Eingabeformular mit einer Schaltfläche zum Absenden anzuzeigen. Sie können die Verify-Seite um sie jetzt zu sehen.
Nun, da wir unsere Seite zur Eingabe unseres Verify-Codes haben, müssen wir nur noch den mit Nexmo gelieferten Code verifizieren. Ersetzen Sie Ihre verify Methode in VerifyController durch den folgenden Code. Diese Methode prüft, ob die eingehenden Daten 4 Zeichen lang sind (Nexmo-Verifizierungscodes können 4 oder 6 Zeichen lang sein, ich arbeite mit 4) und überprüft dann den bereitgestellten Code mit Nexmo. Wenn er nicht gültig ist, wird eine Ausnahme ausgelöst und wir geben dem Benutzer eine Fehlermeldung zurück. Andernfalls holen wir die Benutzer-ID aus der Sitzung, melden den Benutzer an und leiten ihn zum Home-Controller weiter.
public function verify(Request $request) {
$this->validate($request, [
'code' => 'size:4',
]);
try {
Nexmo::verify()->check(
$request->session()->get('verify:request_id'),
$request->code
);
Auth::loginUsingId($request->session()->pull('verify:user:id'));
return redirect('/home');
} catch (Nexmo\Client\Exception\Request $e) {
return redirect()->back()->withErrors([
'code' => $e->getMessage()
]);
}
}Zu diesem Zeitpunkt sollte unsere Integration durchgängig funktionieren. Wenn Sie alle Ihre Änderungen speichern und versuchen, sich anzumelden, sollten Sie auf die verify Seite weitergeleitet werden und eine Textnachricht mit Ihrem Verifizierungscode erhalten. Geben Sie den Code ein und Sie werden wie erwartet eingeloggt.
Herzlichen Glückwunsch! Sie haben gerade die Zwei-Faktor-Authentifizierung mit Nexmo Verify in Ihre Laravel-Anwendung integriert.
Aufräumen der Ecken und Kanten
Es funktioniert zwar, aber es gibt noch einige Unzulänglichkeiten zu beheben. So kann sich ein Nutzer beispielsweise ein zweites Mal anmelden, ohne die erste Verify-Anfrage zu bestätigen. Er kann auch auf die Seite /verify Seite gelangen, ohne eine aktive Verify-Anfrage zu haben. Und schließlich wird die Identität des Nutzers nicht nach der Anmeldung überprüft, sondern erst, wenn er sich abmeldet und erneut versucht, sich anzumelden.
Wir werden diese Probleme in diesem Beitrag nicht lösen - ich lasse sie als Übung für Sie stehen!
Teilen Sie:
Michael ist ein polyglotter Software-Ingenieur, der sich dafür einsetzt, die Komplexität von Systemen zu reduzieren und sie berechenbarer zu machen. Er arbeitet mit einer Vielzahl von Sprachen und Tools und gibt sein technisches Fachwissen auf Benutzergruppen und Konferenzen in der ganzen Welt weiter. Im Alltag ist Michael ein ehemaliger Developer Advocate bei Vonage, wo er seine Zeit damit verbrachte, über alle Arten von Technologie zu lernen, zu lehren und zu schreiben.
