为什么Node中的PassportJS在注销时不会删除会话

我无法让我的系统使用PassportJS注销。 似乎注销路由正在被调用,但它不会删除会话。 我想要它返回401,如果用户没有login在特定的路线。 我调用authenticateUser来检查用户是否login。

非常感谢!

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

布莱斯的答案很好 ,但我仍然注意到一个重要的区别。 护照指南build议使用.logout() (也别名为.logOut() ):

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

但是如上所述,这是不可靠的。 我发现在执行Brice的这个build议时performance得如预期一样:

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

希望这可以帮助!

跑到同一个问题。 使用req.session.destroy(); 而不是req.logout(); 作品,但我不知道这是否是最佳做法。

session.destroy可能不足,为了确保用户完全注销,还必须清除会话cookie。

这里的问题是,如果您的应用程序也被用作单页面应用程序的API(不推荐,但相当常见),那么可能会有一些请求被快速处理,在注销之前开始,在注销之后结束。 如果是这种情况,那么这个长时间运行的请求将在redis被删除后恢复会话。 而且由于浏览器在下次打开页面时仍具有相同的cookie,您将成功login。

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

这是可能发生的事情,否则:

  1. 需求1(任何请求)收到
  2. 需求1将会话从redis加载到内存
  3. 注销req收到
  4. 注销req加载会话
  5. 注销req破坏会话
  6. 注销req发送redirect到浏览器(cookie不会被删除)
  7. 需求1完成处理
  8. 需求1将会话从内存保存到redis
  9. 用户在没有login对话框的情况下打开页面,因为cookie和会话都已经到位

理想情况下,您需要对api调用使用令牌身份validation,并且仅在仅添加页面的web应用程序中使用会话,但即使您的web应用程序仅用于获取api令牌,这种竞争条件仍然是可能的。

我有同样的问题,资本O固定它;

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

我有同样的问题,事实certificate,根本不是护照function的问题,而是以我呼叫/logout路线的方式。 我用fetch来调用路由:

(坏)

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

原来这样做不会发送cookie,所以会话不会继续,我猜res.logout()会被应用到不同的会话? 无论如何,做下面的事情可以解决它:

(好)

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

我使用了req.logout()req.session.destroy()并正常工作。

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

只要提到,我使用Redis作为会话存储。

我最近有这个相同的问题,没有答案解决了我的问题。 可能是错的,但似乎与竞争条件有关。

将会话详细信息更改为以下选项似乎已经解决了我的问题。 我已经testing了10次左右,现在一切似乎都正常。

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

基本上我只是改变了saveUninitializedresavetruefalse 。 这似乎已经解决了这个问题。

仅供参考,我使用的是标准的req.logout(); 方法在我的注销path。 我没有像其他人提到的那样使用会话摧毁。

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

我有一个经验,有时候这是不行的,因为你没有正确设置护照。 例如,我做vhost ,但在主要的应用程序,我设置这样的护照是错误的。

app.js (为什么错?请参阅下面的blockqoute)

 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'))); 

实际上,它一定不能login,但我设法做到这一点,因为我继续犯更多的错误。 通过在这里放置另一个护照设置,所以会话表单app.js可用于app.host.sub1.js

app.host.sub1.js

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

所以,当我想注销…这是行不通的,因为app.js是做错了,在express-session.js之前开始初始化passport.js ,这是错误的!

但是,正如其他人所说,这个代码可以解决问题。

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('/'); }); }); 

但在我的情况下,正确的方法是…在passport.js之前交换express-session.js

文件也提到

请注意,启用会话支持完全是可选的,尽pipe它对于大多数应用程序是推荐的。 如果启用,请务必在passport.session()之前使用express.session(),以确保login会话以正确的顺序恢复。

所以,解决我的情况下注销问题..

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.host.sub1.js

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

现在req.logout(); 现在是工作。

我有同样的问题。 原来,我的护照版本与Express 4.0不兼容。 只需要安装一个旧版本。

  npm install --save express@3.0.0 

破坏会议自己看起来很奇怪。 我面临有下一个configuration的这个问题:

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

我应该说这个configuration工作得很好 。 我的问题的原因是我在这里定义的自定义sessionStore

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

为了确保你的问题在这里也只是评论商店线和运行没有会议坚持。 如果它能起作用,你应该深入你的自定义会话存储。 在我的情况下, set方法被定义为错误的。 当你使用req.logout()会话存储的destroy()方法不像我以前所想的那样被调用。 而是使用更新的会话调用set方法。

祝你好运,我希望这个答案会帮助你。

这对我工作:

 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'); }); 

它确保您的页面不会被存储在caching中

我不知道如何,但ng-href="/signout"解决了我的问题。 以前,我使用服务来注销,但我直接使用它。

在我的情况下,使用传递给req.session.destroy的callback只有一些时间,我不得不采取这个黑客:

 req.session.destroy(); setTimeout(function() { res.redirect "/"; }, 2000); 

我不知道为什么这是我能够开展工作的唯一解决scheme,但不幸的是,@ JulianLloyd的回答对我来说一直不起作用。

这可能与我的活动login页面使用SSL(我还没有能够在暂存站点或本地主机上重现问题)有关。 在我的应用程序中可能还有其他事情正在进行。 我使用德比护照模块,因为我的应用程序正在使用Derby框架,所以很难找出问题。

这显然是一个计时问题,因为我第一次尝试超时100毫秒,这是不够的。

不幸的是,我还没有find更好的解决scheme。