it-swarm.com.de

Erstellen Sie eine sichere API mit passport.js und express.js (node.js).

Ich habe ein spezifisches Problem, es sei denn, ich mache die Dinge nicht richtig.

Ich habe eine Anwendung mit 2 Seiten, einen Client (HTML-Site) und eine API (erstellt mit Express + Mongodb). Es muss sicher auf die API zugegriffen werden. Beide befinden sich auf unterschiedlichen Domains. Nehmen wir jetzt an, meine Website befindet sich auf domain.com und meine API auf api.com:3000.

Ich habe einen Pass hinzugefügt, um ein Zugriffstoken von Github zu erhalten, während ich meine Benutzer mit ihren Daten erstelle, sodass ich grundsätzlich ein "Anmelden bei Github" haben kann.

Mein aktueller Prozess ist:

1) Der Client (die Site) öffnet ein Popup auf der API

window.open("http://api.com:3000/oauth")

2) Starten Sie den Express-Server mit dem Pass-Prozess:

app.get('/oauth', passport.authenticate('github'), function(req, res) {

});

Für die Strategie habe ich diesen Code verwendet.

3) Ich leite den Callback zu einer URL um, die das Popup schließt (Javascript mit einem window.close ()):

app.get('/oauth/callback', passport.authenticate('github', { failureRedirect: '/' }), function(req, res) {
    res.redirect('/auth_close');
});

An diesem Punkt ist alles in Ordnung, ich bin jetzt in der API angemeldet. Mein Problem ist, wie man Daten an den Client zurücksendet, da der Client noch nichts über accessToken, Benutzer oder Benutzer-ID weiß.

Also habe ich vom Client (der Site, die das Popup öffnet) verschiedene Ansätze ausprobiert:

  • einen Wert aus dem Popup bekommen: funktioniert nicht wegen der Weiterleitung, ich verliere den Überblick über die Popup-Javascript-Informationen

  • aufruf meiner API zum Abrufen des "aktuellen Benutzers" in der Sitzung, z. B. http://api.com:3000/current Eine weitere Anforderung ist nicht ideal, aber diese funktioniert. Ich habe jedoch immer noch ein Problem.

Diese/aktuelle URL gibt den Benutzer zurück, wenn ich ihn vom Browser aus erreicht habe, da der Browser in der Kopfanforderung das Express-Session-Cookie sendet:

Cookie:connect.sid=s%3AmDrM5MRA34UuNZqiL%2BV7TMv6.Paw6O%2BtnxQRo0vYNKrher026CIAnNsHn4OJdptb8KqE

Das Problem ist, dass ich diese Anfrage von Jquery oder ähnlichem machen muss, und da schlägt die Sitzung fehl, weil die Sitzung nicht gesendet wird. Der Benutzer wird also nicht zurückgegeben:

app.get('/current', function() {
    // PROBLEM HERE, req.user is undefined with ajax calls because of the session!
});

Ich habe einen Weg gefunden, damit es funktioniert, aber ich bin nicht zufrieden damit, weil ich CORS-Probleme mit Cross-Browsern habe. Es fügt hinzu:

res.header("Access-Control-Allow-Credentials", "true");

Fügen Sie das withCredentials-Feld in einem Jquery-Ajax-Aufruf hinzu, wie erklärt hier .

Eine Zuordnung von fieldName-fieldValue-Paaren für das native XHR-Objekt. Sie können es beispielsweise verwenden, um withCredentials für domänenübergreifende Anforderungen auf true zu setzen.

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

Ich bin auch nicht zufrieden damit, da ich den Platzhalter in meinem Header verliere: Access-Control-Allow-Origin, ich muss eine Domäne angeben, wie erklärt hier .

Ich bin mir also nicht sicher, welchen Ansatz ich hier einschlagen sollte. Das einzige, was ich brauche, ist, dass der Client entweder ein AccessToken oder eine Benutzer-ID aus dem Pass-Pass-Prozess erhält. Die Idee besteht darin, dieses Token bei jedem Aufruf der API zu verwenden, um die Aufrufe zu überprüfen.

Irgendeine Ahnung?

17
Soundstep

Ich hatte das gleiche Problem. Ich habe die lokale Strategie auf der Anmeldeseite verwendet und dann überprüft, ob sich der Benutzer zu anderen Anforderungen in der Sitzung befand.

Wie Sie sagen, besteht die Lösung darin, CORS zu verwenden, damit die Sitzungs-ID mithilfe von XMLHTTPRequest in einem Cookie übergeben wird.

Anstatt den CORS zu verwenden, der noch nicht bei allen Browsern funktioniert, habe ich versucht, Zugriffstoken für andere Anfragen zu verwenden. Der verwendete Workflow ist wie folgt:

POST /login
  • Benutzername und Passwort werden im Body übergeben.
  • Authentifizierung mit lokaler Strategie.
  • Response gibt das Benutzerobjekt zurück, einschließlich des access_token

GET/Endpunkt/abc123? Access_token = abcdefg

  • Token aus der Login-Antwort erhalten
  • Authentifizierung mit der Bearer-Strategie (im Pass-http-Bearer)

In Express werden jetzt keine Sitzungen benötigt.

Ich hoffe diese Alternative hilft.

13
Scott Switzer

Verwenden Sie vor der Konfiguration von Elementen in der Express-App den folgenden (genau gleichen), um den Antwortheader für domänenübergreifend festzulegen:

app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.Origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
     res.send(200);
 } else {
     next();
 }
});
1
sam100rav