Warum entfernt PassportJS in Node die Sitzung beim Abmelden nicht

Lesezeit: 7 Minuten

Benutzer-Avatar
Jeffrey Chen

Ich habe Probleme, mein System dazu zu bringen, sich mit PassportJS abzumelden. Es scheint, dass die Abmelderoute aufgerufen wird, die Sitzung jedoch nicht entfernt wird. Ich möchte, dass 401 zurückgegeben wird, wenn der Benutzer nicht in einer bestimmten Route angemeldet ist. Ich rufe authenticateUser an, um zu prüfen, ob der Benutzer angemeldet ist.

Danke vielmals!

/******* This in index.js *********/
// setup passport for username & passport authentication
adminToolsSetup.setup(passport);

// admin tool login/logout logic
app.post("/adminTool/login",
    passport.authenticate('local', {
        successRedirect: '/adminTool/index.html',
        failureRedirect: "https://stackoverflow.com/",
        failureFlash: false })
);
app.get('/adminTool/logout', adminToolsSetup.authenticateUser, function(req, res){
    console.log("logging out");
    console.log(res.user);
    req.logout();
    res.redirect("https://stackoverflow.com/");
});


// ******* This is in adminToolSetup ********
// Setting up user authentication to be using user name and passport as authentication method,
// this function will fetch the user information from the user name, and compare the password     for authentication
exports.setup = function(passport) {
    setupLocalStrategy(passport);
    setupSerialization(passport);
}

function setupLocalStrategy(passport) {
    passport.use(new LocalStrategy(
        function(username, password, done) {
            console.log('validating user login');
            dao.retrieveAdminbyName(username, function(err, user) {
                if (err) { return done(err); }
                if (!user) {
                    return done(null, false, { message: 'Incorrect username.' });
                }
                // has password then compare password
                var hashedPassword = crypto.createHash('md5').update(password).digest("hex");
                if (user.adminPassword != hashedPassword) {
                    console.log('incorrect password');
                    return done(null, false, { message: 'Incorrect password.' });
                }
                console.log('user validated');
                return done(null, user);
            });
        }
    ));
}

function setupSerialization(passport) {
    // serialization
    passport.serializeUser(function(user, done) {
        console.log("serialize user");
        done(null, user.adminId);
    });

    // de-serialization
    passport.deserializeUser(function(id, done) {
        dao.retrieveUserById(id, function(err, user) {
            console.log("de-serialize user");
            done(err, user);
        });
    });
}

// authenticating the user as needed
exports.authenticateUser = function(req, res, next) {
    console.log(req.user);
    if (!req.user) {
        return res.send("401 unauthorized", 401);
    }
    next();
}

  • In meinem Code rufe ich an req.logOut() mit Großbuchstaben O, aber in Bezug auf die führen Dein Code sollte auch funktionieren.

    – Balas

    11. Januar 2013 um 12:10 Uhr

  • Ich habe viele Lösungen ausprobiert, aber keine davon hat bei mir funktioniert. Schließlich habe ich versucht, das Paket [email protected] auf [email protected] zu aktualisieren, und es funktioniert!

    – prisan

    8. April 2018 um 2:01 Uhr

Brices Antwort ist großartig, aber mir ist noch eine wichtige Unterscheidung aufgefallen; Der Passport-Leitfaden schlägt die Verwendung vor .logout() (auch alias .logOut()) als solche:

app.get('/logout', function(req, res){
  req.logout();
  res.redirect("https://stackoverflow.com/"); //Can fire before session is destroyed?
});

Aber wie oben erwähnt, ist dies unzuverlässig. Ich fand, dass es sich wie erwartet verhielt, als ich Brices Vorschlag wie folgt umsetzte:

app.get('/logout', function (req, res){
  req.session.destroy(function (err) {
    res.redirect("https://stackoverflow.com/"); //Inside a callback… bulletproof!
  });
});

Hoffe das hilft!

  • Als Fehlermeldung bekomme ich nur ‘Object # has no method ‘destroy’

    – schlenger

    13. November 2014 um 16:02 Uhr

  • @schlenger Hmm, oben wird Express 3 verwendet. Verwenden Sie Version 4?

    – jlmacht

    13. November 2014 um 22:32 Uhr

  • Seien Sie vorsichtig, da in dem hier angegebenen Beispiel die Verwendung von session.destroy die Verwendung des Moduls express-sessions voraussetzt. Andere Sitzungsmodule (z. B. Mozilla-Knoten-Client-Sitzungen) fügen eine Destroy-Methode hinzu, die nur synchron zurückkehrt und alle Callback-Parameter ignoriert. In diesem Fall wird Ihr Code hängen bleiben

    – Fröhlich

    5. März 2017 um 19:58 Uhr


  • Beruhst du darauf client-sessions? Seine Destroy-Funktion akzeptiert kein Argument: github.com/mozilla/node-client-sessions/blob/master/lib/…

    – oztune

    24. Januar 2018 um 23:48 Uhr

  • ok ich benutze deine zweite Methode. Die Sitzungsdatei im Sitzungsordner wird gelöscht und das Sitzungscookie wird vom Client entfernt, aber der Knotenserver zeigt die folgende Fehlermeldung in der Konsole an: [session-file-store] will retry, error on last attempt: Error: ENOENT: no such file or directory, open ... wie könnte ich das beheben?

    – emonhossain

    18. Mai 2020 um 11:21 Uhr

Benutzer-Avatar
Brice

Bin auf das gleiche Problem gestoßen. Verwenden req.session.destroy(); Anstatt von req.logout(); funktioniert, aber ich weiß nicht, ob dies die beste Methode ist.

  • Hinzufügen von req.session.destroy(); hat bei mir funktioniert, ich hatte das gleiche Problem

    – Michael

    4. September 2013 um 20:36 Uhr

  • req.session.destroy(); hat auch bei mir funktioniert und denken Sie daran, Ihre Cookies mit res.clearCookie(‘cookiename’) zu löschen. Aber weiß jemand, was genau req.logout() tut?

    – Hrushikesh

    5. Dezember 2013 um 23:19 Uhr

  • @WebHrushi Sie finden die Funktion in Passport/lib/passport/http/request.js. Heute funktionieren beide Versionen bei mir nicht mehr, Redirect scheint in beiden Richtungen aufgerufen zu werden, bevor die Session endgültig zerstört wird. Auf der umgeleiteten Seite scheinen beide hier beschriebenen Wege gut zu funktionieren.

    – ztirom

    20. Dezember 2013 um 12:28 Uhr


  • Ich mag die Idee nicht, es nicht zu verwenden req.logout()für die Aufwärtskompatibilität und so weiter, also habe ich gerade hinzugefügt req.session.destroy(); nach req.logout() und das funktioniert gut.

    – Gawin

    13. Juni 2014 um 12:05 Uhr

session.destroy möglicherweise nicht ausreicht, um sicherzustellen, dass der Benutzer vollständig abgemeldet ist, müssen Sie auch das Sitzungscookie löschen.

Das Problem hier ist, dass, wenn Ihre Anwendung auch als API für eine Single-Page-App verwendet wird (nicht empfohlen, aber ziemlich häufig), dann einige Anfragen von Express verarbeitet werden können, die vor dem Abmelden begonnen und nach dem Abmelden enden. Wenn dies der Fall wäre, stellt diese länger laufende Anfrage die Sitzung in redis wieder her, nachdem sie gelöscht wurde. Und weil der Browser immer noch das gleiche Cookie hat, werden Sie beim nächsten Öffnen der Seite erfolgreich angemeldet.

req.session.destroy(function() {
    res.clearCookie('connect.sid');
    res.redirect("https://stackoverflow.com/");
});

Das ist das, was vielleicht sonst passiert:

  1. Req 1 (jede Anfrage) wird empfangen
  2. Req 1 lädt die Sitzung von Redis in den Speicher
  3. Abmeldeanforderung erhalten
  4. Logout req lädt Sitzung
  5. Abmeldeanforderung zerstört Sitzung
  6. Abmeldeanforderung sendet Weiterleitung an den Browser (Cookie wird nicht entfernt)
  7. Req 1 schließt die Verarbeitung ab
  8. Req 1 speichert die Sitzung aus dem Speicher in redis
  9. Der Benutzer öffnet die Seite ohne Anmeldedialog, da sowohl das Cookie als auch die Sitzung vorhanden sind

Idealerweise müssen Sie die Token-Authentifizierung für API-Aufrufe verwenden und nur Sitzungen in der Web-App verwenden, die nur Seiten lädt, aber selbst wenn Ihre Web-App nur zum Abrufen von API-Token verwendet wird, ist diese Race-Bedingung immer noch möglich.

  • Dies löst das Problem auf dem Client und nicht auf dem Server, der unsicher erscheint. wenn connect.sid entführt wird, bevor Sie sich abmelden, sollte es keiner anderen Partei erlauben, sich als Sie anzumelden, nachdem Sie sich abgemeldet haben.

    – Paul S

    23. Mai 2018 um 20:46 Uhr


Ich hatte das gleiche Problem, und es stellte sich heraus, dass es überhaupt kein Problem mit den Passport-Funktionen war, sondern eher mit der Art und Weise, wie ich meine anrief /logout Route. Ich habe fetch verwendet, um die Route aufzurufen:

(Schlecht)

fetch('/auth/logout')
  .then([other stuff]);

Es stellt sich heraus, dass dabei keine Cookies gesendet werden, sodass die Sitzung nicht fortgesetzt wird, und ich denke, das res.logout() wird auf eine andere Sitzung angewendet? Auf jeden Fall behebt es Folgendes, wenn Sie Folgendes tun:

(Gut)

fetch('/auth/logout', { credentials: 'same-origin' })
  .then([other stuff]);

Benutzer-Avatar
abitofcode

Ich hatte die gleichen Probleme, Capital O hat es behoben;

app.get('/logout', function (req, res){
  req.logOut()  // <-- not req.logout();
  res.redirect("https://stackoverflow.com/")
});

Edit: Das ist kein Thema mehr.

  • Die aktuelle Version von Passport akzeptiert entweder LogOut oder Logout (dasselbe gilt für Login und LogIn)

    – Cyberwombat

    8. Dezember 2014 um 3:48 Uhr

  • logout und logOut wurden 2015 miteinander aliasiert: github.com/jaredhanson/passport/blame/…

    – Paul S

    23. Mai 2018 um 20:56 Uhr


Benutzer-Avatar
Venryx

Ich habe beides verwendet req.logout() und req.session.destroy() und funktioniert gut.

server.get('/logout', (req, res) => {
  req.logout();
  req.session.destroy(()=>{
    res.redirect("https://stackoverflow.com/");
  });
});

Nur um zu erwähnen, dass ich Redis als Sitzungsspeicher verwende.

  • Die aktuelle Version von Passport akzeptiert entweder LogOut oder Logout (dasselbe gilt für Login und LogIn)

    – Cyberwombat

    8. Dezember 2014 um 3:48 Uhr

  • logout und logOut wurden 2015 miteinander aliasiert: github.com/jaredhanson/passport/blame/…

    – Paul S

    23. Mai 2018 um 20:56 Uhr


Benutzer-Avatar
Charlie Fisch

Ich hatte kürzlich dasselbe Problem und keine der Antworten hat das Problem für mich behoben. Könnte falsch sein, aber es scheint mit einer Rennbedingung zu tun zu haben.

Das Ändern der Sitzungsdetails in die folgenden Optionen scheint das Problem für mich behoben zu haben. Ich habe es jetzt ungefähr 10 Mal oder so getestet und alles scheint richtig zu funktionieren.

app.use(session({
    secret: 'secret',
    saveUninitialized: false,
    resave: false
}));

Im Grunde habe ich mich gerade verändert saveUninitialized und resave aus true zu false. Das scheint das Problem behoben zu haben.

Nur als Referenz verwende ich den Standard req.logout(); Methode in meinem Abmeldepfad. Ich verwende die Sitzungszerstörung nicht, wie andere Leute erwähnt haben.

app.get('/logout', function(req, res) {
    req.logout();
    res.redirect("https://stackoverflow.com/");
});

  • Ich hatte Probleme mit Abmeldung und Anmeldung, die gelegentlich nicht hängen blieben, und das hat es für mich behoben.

    – Tom Hughes

    24. Mai 2017 um 17:27 Uhr

  • @TomHughes Schön, dass es geholfen hat!!

    – Charlie Fisch

    24. Mai 2017 um 19:44 Uhr

1018200cookie-checkWarum entfernt PassportJS in Node die Sitzung beim Abmelden nicht

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy