web-dev-qa-db-de.com

Warum entfernt PassportJS in Node keine Sitzung beim Abmelden?

Ich kann mein System nicht mit PassportJS abmelden. Es scheint, dass die Abmelde-Route aufgerufen wird, die Sitzung jedoch nicht entfernt wird. Ich möchte 401 zurückgeben, 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: '/',
        failureFlash: false })
);
app.get('/adminTool/logout', adminToolsSetup.authenticateUser, function(req, res){
    console.log("logging out");
    console.log(res.user);
    req.logout();
    res.redirect('/');
});


// ******* 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();
}
59
Jeffrey Chen

Brices Antwort ist großartig , aber ich habe immer noch einen wichtigen Unterschied bemerkt, den ich machen muss. Die Passport-Anleitung schlägt vor, .logout() (auch als .logOut() aliasiert) zu verwenden:

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

Wie oben erwähnt, ist dies jedoch unzuverlässig. Ich fand es wie erwartet, als er den Vorschlag von Brice wie folgt umsetzte:

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

Hoffe das hilft!

72
jlmakes

Lief in die gleiche Ausgabe. Die Verwendung von req.session.destroy(); anstelle von req.logout(); funktioniert, aber ich weiß nicht, ob dies die beste Vorgehensweise ist.

41
Brice

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

Das Problem hierbei ist, dass, wenn Ihre Anwendung auch als API für eine Einzelseiten-App verwendet wird (nicht empfohlen, aber recht häufig), möglicherweise einige Anforderungen von Express verarbeitet werden, die vor der Abmeldung und nach der Abmeldung gestartet wurden. Wenn dies der Fall war, stellt diese länger laufende Anforderung die Sitzung nach dem Löschen wieder her. Und da der Browser beim nächsten Öffnen der Seite immer noch den gleichen Cookie enthält, werden Sie erfolgreich angemeldet.

req.session.destroy(function() {
    res.clearCookie('connect.sid');
    res.redirect('/');
});

Das ist was sonst vielleicht passiert:

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

Im Idealfall müssen Sie die Tokenauthentifizierung für API-Aufrufe verwenden und nur Sitzungen in einer Web-App verwenden, die nur Seiten laden. Selbst wenn Ihre Web-App nur zum Erhalt von API-Tokens verwendet wird, ist diese Race-Bedingung immer noch möglich.

9
esp

Ich hatte das gleiche Problem, und es stellte sich heraus, dass es überhaupt kein Problem mit Passport-Funktionen war, sondern eher in der Art und Weise, wie ich meine /logout-Route aufrief. Ich habe die Route mit Fetch aufgerufen:

(Schlecht)

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

Es stellt sich heraus, dass dabei keine Cookies gesendet werden, also wird die Sitzung nicht fortgesetzt und ich denke, die res.logout() wird auf eine andere Sitzung angewendet. Auf jeden Fall können Sie Folgendes tun, indem Sie Folgendes tun:

(Gut)

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

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

app.get('/logout', function (req, res){
  req.logOut()  // <-- not req.logout();
  res.redirect('/')
});
6
abitofcode

Ich hatte kürzlich das gleiche Problem und keine der Antworten hat das Problem für mich behoben. Könnte falsch sein, aber es scheint mit der Rasse 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 getestet und alles scheint richtig zu funktionieren.

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

Grundsätzlich habe ich gerade saveUninitialized und resave von true in false geändert. Das scheint das Problem behoben zu haben.

Nur als Referenz verwende ich die Standardmethode req.logout(); in meinem Abmeldepfad. Ich benutze die Session-Zerstörung nicht wie andere Leute erwähnt haben.

app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/');
});
4
Charlie Fish

Ich habe sowohl req.logout() als auch req.session.destroy() verwendet und funktioniert einwandfrei.

server.get('/logout', (req, res) => {
  req.logout();
  req.session.destroy();
  res.redirect('/');
});

Um nur zu erwähnen, benutze ich Redis als Session Store.

4
sstauross

Die Sitzung selbst zu zerstören, sieht seltsam aus ..

"express": "^4.12.3",
"passport": "^0.2.1",
"passport-local": "^1.0.0",

Ich sollte sagen, dass diese Konfiguration funktioniert gut. Der Grund für mein Problem war in der benutzerdefinierten sessionStore, die ich hier definiert habe:

app.use(expressSession({
    ...
    store: dbSessionStore,
    ...
}));

Um sicher zu sein, dass Ihr Problem auch hier kommentiert, speichern Sie die Zeile und führen Sie sie aus, ohne dass die Sitzung bestehen bleibt. Wenn dies funktioniert, sollten Sie in Ihren benutzerdefinierten Sitzungsspeicher wechseln. In meinem Fall wurde die set-Methode falsch definiert. Wenn Sie die req.logout()-Sitzungsablage verwenden, wird die destroy()-Methode nicht aufgerufen, wie ich vorher gedacht habe. Stattdessen set-Methode mit aktualisierter Sitzung aufgerufen.

Viel Glück, ich hoffe, diese Antwort wird Ihnen helfen.

1
DontRelaX

Ich habe die Erfahrung gemacht, dass es manchmal nicht funktioniert, weil Sie den Pass nicht richtig einrichten können Zum Beispiel mache ich vhost, aber bei der Hauptanwendung stelle ich einen Pass ein, der falsch ist.

app.js (warum falsch? bitte sehen Sie blockqoute weiter unten)

require('./modules/middleware.bodyparser')(app);
require('./modules/middleware.passport')(app);
require('./modules/middleware.session')(app);
require('./modules/app.config.default.js')(app, express);

// default router across domain
app.use('/login', require('./controllers/loginController'));
app.get('/logout', function (req, res) {
    req.logout();
    res.redirect('/');
});

// vhost setup
app.use(vhost('sub1.somehost.dev', require('./app.Host.sub1.js')));
app.use(vhost('somehost.dev', require('./app.Host.main.js')));

eigentlich muss es nicht möglich sein, sich anzumelden, aber ich schaffe das, weil ich weiterhin Fehler mache. indem Sie hier ein anderes Pass-Setup eingeben, so dass das Sitzungsformular app.js für app.Host.sub1.js verfügbar ist.

app.Host1.js

// default app configuration
require('./modules/middleware.passport')(app);
require('./modules/app.config.default.js')(app, express);

Wenn ich mich also abmelden möchte, funktioniert es nicht, weil app.js etwas falsch gemacht hat, indem Sie passport.js vor express-session.js initialisieren, was falsch ist !!.

Dieser Code kann jedoch die Probleme trotzdem lösen, wie andere bereits erwähnen.

app.js

app.get('/logout', function (req, res) {
    req.logout();
    req.session.destroy(function (err) {
        if (err) {
            return next(err);
        }

        // destroy session data
        req.session = null;

        // redirect to homepage
        res.redirect('/');
    });
});

Aber in meinem Fall ist der richtige Weg ... tauschen Sie die express-session.js vor passport.js

Dokument auch erwähnen

Beachten Sie, dass die Aktivierung der Sitzungsunterstützung vollständig optional ist, obwohl es .__ ist. empfohlen für die meisten Anwendungen. Falls aktiviert, verwenden Sie unbedingt __. express.session () vor passport.session (), um sicherzustellen, dass das Login Sitzung wird in der richtigen Reihenfolge wiederhergestellt.

Also, Logout-Problem in meinem Fall gelöst durch ..

app.js

require('./modules/middleware.bodyparser')(app);
require('./modules/middleware.session')(app);
require('./modules/middleware.passport')(app);
require('./modules/app.config.default.js')(app, express);


// default router across domain
app.use('/login', require('./controllers/loginController'));
app.get('/logout', function (req, res) {
    req.logout();
    res.redirect('/');
});

app.Host1.js

// default app configuration
require('./modules/app.config.default.js')(app, express);

und jetzt funktioniert req.logout(); jetzt.

1
Jongz Puangput

Ich hatte das gleiche Problem. Es stellte sich heraus, dass meine Passversion nicht mit Express 4.0 kompatibel war. Sie müssen nur eine ältere Version installieren.

    npm install --save [email protected]
0
Ryan

Das hat für mich funktioniert:

app.get('/user', restrictRoute, function (req, res) {
  res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate,
              max-stale=0, post-check=0, pre-check=0');
});

Dadurch wird sichergestellt, dass Ihre Seite nicht im Cache gespeichert wird

0

Alle Beispiele hier führen eine Umleitung nach der req.session.destroy durch. Beachten Sie jedoch, dass Express sofort eine neue Sitzung für die Seite erstellt, zu der Sie weiterleiten. In Verbindung mit Postman fand ich das merkwürdige Verhalten, dass ein Passport-Login direkt nach der Abmeldung bewirkt, dass Passport erfolgreich ist, aber die Benutzer-ID nicht in der Sitzungsdatei speichern kann. Der Grund ist, dass Postman das Cookie in allen Anforderungen für diese Gruppe aktualisieren muss. Dies dauert eine Weile. Auch die Umleitung im Callback des Destroy hilft nicht. 

Ich habe es gelöst, indem ich keine Weiterleitung ausführte, sondern nur eine Json-Nachricht zurücksende.

0
BertC

Anscheinend gibt es mehrere mögliche Ursachen für dieses Problem. In meinem Fall lag das Problem in der falschen Reihenfolge der Deklarationen, d. H. Der Endpunkt der Abmeldung wurde vor der Initialisierung des Passes deklariert. Die richtige Reihenfolge ist:

app.use(passport.initialize());
app.use(passport.session());


app.get('/logout', function(req, res) {
  req.logout();
  res.redirect('/');
});
0

Sie sollten req.logout () verwenden, um die Sitzung im Browser zu zerstören.

app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/'); // whatever the route to your default page is
});
0
Anuj Kumar

Ich arbeite mit einem Programmierer, der vorschlägt, Benutzer von req zu entfernen:

app.get('/logout', function (req, res){
  req.session.destroy(function (err) {
    req.user = null;
    res.redirect('/'); //Inside a callback… bulletproof!
  });
});

Grund: Wir müssen aus req entfernen (Passwörter auch auf asynchrone Art und Weise), da nach der Abmeldung keine Benutzerdaten verwendet werden. __ und kann eine neue Sitzung erstellen und umleiten (aber noch nicht geschehen). Dies ist in unserer Verantwortung, irrelevante Dinge zu entfernen. PassportJS weist req.user nach dem Login Daten zu und entfernt sie auch, wenn wir req.logout () verwenden, aber es funktioniert manchmal nicht richtig als NodeJS Asynchronous

0
mrmccormack

Ich hatte ein ähnliches Problem mit Passport 0.3.2.

Wenn ich Custom Callback für die Passport-Anmeldung und die Anmeldung verwende, blieb das Problem bestehen.

Das Problem wurde durch ein Upgrade auf Passport 0.4.0 und das Hinzufügen der Zeilen behoben

app.get('/logout', function(req, res) {
    req.logOut();
    res.redirect('/');
});
0
Venu

Keine der Antworten funktionierte für mich, daher werde ich meine weitergeben

app.use(session({
    secret: 'some_secret',
    resave: false,
    saveUninitialized: false,
   cookie: {maxAge: 1000} // this is the key
}))

und

router.get('/logout', (req, res, next) => {
    req.logOut()
    req.redirect('/')
})
0
user1733031

Da Sie die Passport-Authentifizierung verwenden, bei der die eigene Sitzung über den connect.sid-Cookie verwendet wird, besteht die einfachste Möglichkeit zum Abmelden darin, dass Passport die Sitzung behandelt.

app.get('/logout', function(req, res){
  if (req.isAuthenticated()) {
    req.logOut()
    return res.redirect('/') // Handle valid logout
  }

  return res.status(401) // Handle unauthenticated response
})
0
acharlop