wake-up-neo.com

passport.js RESTful auth

Wie geht man mit der Authentifizierung (z. B. lokal und Facebook) über passport.js über eine RESTful-API anstatt über eine Webschnittstelle um?

Besondere Bedenken betreffen die Weitergabe von Daten von Rückrufen an eine RESTful-Antwort (JSON) im Gegensatz zur Verwendung eines typischen res.send-Endpunkts ({data: req.data}), bei dem ein initialer/login-Endpunkt eingerichtet wird, der zu Facebook umleitet (/ login kann nicht sein) Zugriff über AJAX, da es sich nicht um eine JSON-Antwort handelt - es handelt sich um eine Weiterleitung zu Facebook mit einem Rückruf.

Ich habe https://github.com/halrobertson/test-restify-passport-facebook gefunden, aber ich habe Probleme, es zu verstehen.

Wie speichert passport.js außerdem die Anmeldeinformationen für die Authentifizierung? Der Server (oder ist es ein Dienst?) Wird von MongoDB unterstützt, und ich würde erwarten, dass Anmeldeinformationen (Login und gesalzener Hash von pw) dort gespeichert werden, aber ich weiß nicht, ob passport.js über diese Art von Funktionen verfügt.

155
ryanrhee

Hier werden viele Fragen gestellt, und obwohl die Fragen im Kontext von Node und passport.js gestellt werden, geht es bei den eigentlichen Fragen eher um den Arbeitsablauf als darum, wie dies mit einem bestimmten Element geschehen soll Technologie.

Verwenden wir das @ Keith-Beispielsetup, das aus Sicherheitsgründen ein wenig modifiziert wurde:

  • Der Webserver bei https://example.com Bedient eine einseitige Javascript-Client-App
  • Der RESTful-Webdienst unter https://example.com/api Bietet Serverunterstützung für die Rich-Client-App
  • Server implementiert in Node und passport.js.
  • Der Server verfügt über eine Datenbank (beliebiger Art) mit einer "Benutzer" -Tabelle.
  • Benutzername/Passwort und Facebook Connect werden als Authentifizierungsoptionen angeboten
  • Rich Client macht REST Anfragen in https://example.com/api
  • Möglicherweise verwenden andere Clients (z. B. Telefon-Apps) den Webdienst unter https://example.com/api, Kennen den Web-Server unter https://example.com Jedoch nicht.

Beachten Sie, dass ich sicheres HTTP verwende. Dies ist meiner Meinung nach ein Muss für jeden Service, der im Freien verfügbar ist, da vertrauliche Informationen wie Passwörter und Autorisierungstoken zwischen Client und Server übertragen werden.

Benutzername/Passwort-Authentifizierung

Schauen wir uns zunächst an, wie die einfache alte Authentifizierung funktioniert.

  • Der Benutzer verbindet sich mit https://example.com
  • Der Server stellt eine umfangreiche Javascript-Anwendung bereit, mit der die Startseite gerendert wird. Irgendwo auf der Seite gibt es ein Anmeldeformular.
  • Viele Abschnitte dieser einseitigen App wurden nicht mit Daten gefüllt, da der Benutzer nicht angemeldet ist. Alle diese Abschnitte haben einen Ereignis-Listener für ein "Login" -Ereignis. All dies ist clientseitiges Material, der Server kennt diese Ereignisse nicht.
  • Der Benutzer gibt seinen Benutzernamen und sein Kennwort ein und klickt auf die Schaltfläche zum Senden, wodurch ein Javascript-Handler zum Aufzeichnen des Benutzernamens und des Kennworts in clientseitigen Variablen ausgelöst wird. Dieser Handler löst dann das Ereignis "login" aus. Auch dies ist alles clientseitige Aktion, Anmeldeinformationen wurden noch nicht an den Server gesendet .
  • Die Listener des "login" -Ereignisses werden aufgerufen. Jeder dieser Server muss nun eine oder mehrere Anforderungen an die RESTful-API unter https://example.com/api Senden, um die benutzerspezifischen Daten zu erhalten, die auf der Seite gerendert werden sollen. Jede einzelne Anforderung, die sie an den Webdienst senden, enthält den Benutzernamen und das Kennwort, möglicherweise in Form von HTTP Basic Authentifizierung, da der REST-fähige Dienst den Client-Status von einer Anforderung bis zur nicht aufrechterhalten darf Nächster. Da sich der Webdienst auf sicherem HTTP befindet, wird das Kennwort während der Übertragung sicher verschlüsselt.
  • Der Webdienst unter https://example.com/api Empfängt eine Reihe von Einzelanforderungen mit jeweils Authentifizierungsinformationen. Der Benutzername und das Kennwort in jeder Anforderung werden mit der Benutzerdatenbank verglichen. Wenn sie als korrekt befunden werden, wird die angeforderte Funktion ausgeführt und die Daten werden im JSON-Format an den Client zurückgegeben. Wenn Benutzername und Passwort nicht übereinstimmen, wird ein Fehler in Form eines 401-HTTP-Fehlercodes an den Client gesendet.
  • Anstatt Clients zu zwingen, Benutzernamen und Kennwort bei jeder Anforderung zu senden, können Sie in Ihrem RESTful-Dienst die Funktion "get_access_token" verwenden, die den Benutzernamen und das Kennwort verwendet und mit einem Token antwortet, bei dem es sich um eine Art kryptografischen Hash handelt, der eindeutig ist und einen gewissen Ablauf aufweist Datum damit verbunden. Diese Token werden mit jedem Benutzer in der Datenbank gespeichert. Dann sendet der Client das Zugriffstoken in nachfolgenden Anforderungen. Das Zugriffstoken wird dann anhand der Datenbank anstelle des Benutzernamens und des Kennworts validiert.
  • Nicht-Browser-Client-Anwendungen wie Telefon-Apps verhalten sich wie oben beschrieben. Sie fordern den Benutzer auf, seine Anmeldeinformationen einzugeben und diese (oder ein daraus generiertes Zugriffstoken) bei jeder Anforderung an den Webdienst zu senden.

Der wichtige Vorteil dieses Beispiels ist, dass RESTful-Webdienste bei jeder Anforderung eine Authentifizierung erfordern .

Eine zusätzliche Sicherheitsebene in diesem Szenario würde zusätzlich zur Benutzerauthentifizierung eine Clientanwendungsautorisierung hinzufügen. Wenn Sie beispielsweise den Webclient, iOS und Android Apps verwenden, die alle den Webdienst verwenden, möchten Sie möglicherweise, dass der Server weiß, welcher der drei Clients einer bestimmten Anfrage ist, unabhängig davon, wer Dies kann Ihrem Webdienst ermöglichen, bestimmte Funktionen auf bestimmte Clients zu beschränken. Hierzu können Sie API-Schlüssel und Geheimnisse verwenden (siehe diese Antwort ).

Facebook-Authentifizierung

Der obige Workflow funktioniert nicht für Facebook Connect, da der Login über Facebook einen Dritten, Facebook selbst, hat. Um sich anzumelden, muss der Benutzer auf die Website von Facebook umgeleitet werden, auf der außerhalb unserer Kontrolle Anmeldeinformationen eingegeben werden.

Also mal sehen, wie sich die Dinge ändern:.

  • Der Benutzer verbindet sich mit https://example.com
  • Der Server stellt eine umfangreiche Javascript-Anwendung bereit, mit der die Startseite gerendert wird. Irgendwann auf der Seite gibt es ein Login-Formular, das einen "Login mit Facebook" -Button enthält.
  • Der Benutzer klickt auf die Schaltfläche "Anmelden mit Facebook", bei der es sich lediglich um einen Link handelt, der (beispielsweise) zu https://example.com/auth/facebook Weiterleitet.
  • Die Route https://example.com/auth/facebook Wird von passport.js verwaltet (siehe Dokumentation )
  • Der Benutzer sieht lediglich, dass sich die Seite ändert und befindet sich nun auf einer von Facebook gehosteten Seite, auf der er sich anmelden und unsere Webanwendung autorisieren muss. Dies liegt völlig außerhalb unserer Kontrolle.
  • Der Benutzer meldet sich bei Facebook an und erteilt die Berechtigung für unsere Anwendung. Daher leitet Facebook jetzt zurück zu der Rückruf-URL, die wir im Setup von passport.js konfiguriert haben. Dies entspricht dem Beispiel in der Dokumentationhttps://example.com/auth/facebook/callback
  • Der passport.js-Handler für die https://example.com/auth/facebook/callback - Route ruft die Rückruffunktion auf, die das Facebook-Zugriffstoken und einige Benutzerinformationen von Facebook erhält, einschließlich der E-Mail-Adresse des Benutzers.
  • Mit der E-Mail können wir den Nutzer in unserer Datenbank lokalisieren und den Facebook-Zugangstoken damit speichern.
  • Das Letzte, was Sie im Facebook-Rückruf tun, ist, zurück zur Rich-Client-Anwendung zu leiten. Diesmal müssen wir jedoch den Benutzernamen und das Zugriffstoken an den Client übergeben, damit er sie verwenden kann. Dies kann auf verschiedene Arten geschehen. Beispielsweise können der Seite über eine serverseitige Vorlagenengine JavaScript-Variablen hinzugefügt werden, oder es kann ein Cookie mit diesen Informationen zurückgegeben werden. (Vielen Dank an @RyanKimber für den Hinweis auf die Sicherheitsprobleme bei der Weitergabe dieser Daten in der URL, wie ich ursprünglich vorgeschlagen hatte).
  • Jetzt starten wir die App für eine einzelne Seite noch einmal, aber der Client hat den Benutzernamen und das Zugriffstoken.
  • Die Client-Anwendung kann das "Login" -Ereignis sofort auslösen und die verschiedenen Teile der Anwendung die erforderlichen Informationen vom Webdienst anfordern lassen.
  • Alle Anfragen, die an https://example.com/api Gesendet werden, enthalten das Facebook-Zugriffstoken zur Authentifizierung oder das Zugriffstoken der Anwendung, das aus dem Facebook-Token über eine Funktion "get_access_token" in der REST API generiert wurde.
  • Bei Nicht-Browser-Apps ist dies etwas schwieriger, da OAuth zum Anmelden ein Webbrowser erforderlich ist. Um sich von einer Telefon- oder Desktop-App aus anzumelden, muss ein Browser gestartet werden Umleiten zu Facebook, und noch schlimmer, Sie benötigen eine Möglichkeit für den Browser, das Facebook-Zugriffstoken über einen Mechanismus an die Anwendung zurückzuleiten.

Ich hoffe, das beantwortet die meisten Fragen. Natürlich können Sie Facebook durch Twitter, Google oder einen anderen OAuth basierten Authentifizierungsdienst ersetzen.

Es würde mich interessieren, ob jemand einen einfacheren Weg hat, damit umzugehen.

311
Miguel

Ich schätze die Erklärung von @ Miguel mit dem vollständigen Ablauf in jedem Fall sehr, aber ich möchte einige auf dem Facebook-Authentifizierungsteil hinzufügen.

Facebook stellt ein Javascript SDK zur Verfügung, mit dem Sie das Zugriffstoken direkt auf Client-Seite abrufen können. Dieses wird dann an den Server weitergeleitet und verwendet, um alle Benutzerinformationen von Facebook weiter abzurufen. Sie brauchen also grundsätzlich keine Umleitungen.

Darüber hinaus können Sie denselben API-Endpunkt auch für mobile Anwendungen verwenden. Verwenden Sie einfach das Android/iOS SDK für Facebook, besorgen Sie sich das Facebook Access_Token auf der Client-Seite und leiten Sie es an den Server weiter.

In Bezug auf die zustandslose Natur wird dieses Token auch auf dem Server gespeichert, wenn get_access_token zum Generieren eines Tokens verwendet und an den Client übergeben wird. Also ist es so gut wie ein Sitzungstoken und ich glaube, das macht es zustandsbehaftet?

Nur meine 2 Cent ..

11
Madhur

Hier ist ein großartiger Artikel, mit dem Sie sich authentifizieren können:

  • Facebook
  • Twitter
  • Google
  • Lokale Auth

Easy Node Authentication: Setup and Local

3
myusuf