为什么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将会话从redis加载到内存
- 注销req收到
- 注销req加载会话
- 注销req破坏会话
- 注销req发送redirect到浏览器(cookie不会被删除)
- 需求1完成处理
- 需求1将会话从内存保存到redis
- 用户在没有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 }));
基本上我只是改变了saveUninitialized
并resave
从true
到false
。 这似乎已经解决了这个问题。
仅供参考,我使用的是标准的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。