我无法让我的系统使用PassportJS注销。似乎正在调用注销路由,但它不会删除会话。如果用户没有以特定路线登录,我希望它返回401。我调用authenticateUser来检查用户是否已登录。
非常感谢!
/******* 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();
}
答案 0 :(得分:74)
布莱斯的回答很棒,但我仍然注意到要做出的重要区别; Passport指南建议使用.logout()
(也称为.logOut()
):
app.get('/logout', function(req, res){
req.logout();
res.redirect('/'); //Can fire before session is destroyed?
});
但如上所述,这是不可靠的。我发现在执行Brice的建议时它表现得像预期的那样:
app.get('/logout', function (req, res){
req.session.destroy(function (err) {
res.redirect('/'); //Inside a callback… bulletproof!
});
});
希望这有帮助!
答案 1 :(得分:41)
陷入同样的问题。使用req.session.destroy();
代替req.logout();
有效,但我不知道这是否是最佳做法。
答案 2 :(得分:10)
session.destroy
可能不够,为了确保用户完全注销,您还必须清除会话cookie。
这里的问题是,如果您的应用程序也被用作单页面应用程序的API(不推荐但很常见),那么可能会有一些请求由快递处理,在注销之前开始并在注销后结束。如果是这种情况,则此较长时间运行的请求将在删除后以redis还原会话。并且因为下次打开页面时浏览器仍然具有相同的cookie,您将成功登录。
req.session.destroy(function() {
res.clearCookie('connect.sid');
res.redirect('/');
});
否则可能发生的事情是:
理想情况下,您需要对api调用使用令牌身份验证,并且只使用仅加载页面的Web应用程序中的会话,但即使您的Web应用程序仅用于获取api令牌,这种竞争条件仍然存在。
答案 3 :(得分:7)
我遇到了同样的问题,结果证明Passport功能根本不是问题,而是我调用/logout
路由的方式。我使用fetch来调用路由:
<强>(坏)强>
fetch('/auth/logout')
.then([other stuff]);
原来这样做不发送cookie所以会话不会继续,我想res.logout()
会被应用到不同的会话?无论如何,执行以下操作会立即修复它:
<强>(良好)强>
fetch('/auth/logout', { credentials: 'same-origin' })
.then([other stuff]);
答案 4 :(得分:5)
我遇到了同样的问题,资本O修好了它;
app.get('/logout', function (req, res){
req.logOut() // <-- not req.logout();
res.redirect('/')
});
编辑:这不再是一个问题。
答案 5 :(得分:4)
我同时使用req.logout()
和req.session.destroy()
并且工作正常。
server.get('/logout', (req, res) => {
req.logout();
req.session.destroy();
res.redirect('/');
});
简而言之,我使用Redis作为会话存储。
答案 6 :(得分:1)
我得到的经验是,有时因为你没有正确设置护照而无法正常工作。
例如,我做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')));
实际上,它一定不能登录,但我设法做到这一点因为,我继续犯更多错误。通过在此处设置另一个护照设置,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
在passport.js
开始初始化express-session.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
document也提到
请注意,启用会话支持完全是可选的,尽管它是 推荐用于大多数应用。如果启用,请务必使用 express.session()在passport.session()之前确保登录 会话以正确的顺序恢复。
所以,通过..解析了我的案例的注销问题。
<强> 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();
正在运作。
答案 7 :(得分:1)
没有一个答案对我有用,所以我会和我分享
app.use(session({
secret: 'some_secret',
resave: false,
saveUninitialized: false,
cookie: {maxAge: 1000} // this is the key
}))
和
router.get('/logout', (req, res, next) => {
req.logOut()
req.redirect('/')
})
答案 8 :(得分:1)
自己销毁会话看起来很奇怪。 我面临着下一个配置的问题:
"express": "^4.12.3",
"passport": "^0.2.1",
"passport-local": "^1.0.0",
我应该说这个配置效果很好。
我的问题的原因是我在此处定义的自定义sessionStore
:
app.use(expressSession({
...
store: dbSessionStore,
...
}));
为了确保您的问题,这里只是注释商店行并在没有会话持久的情况下运行。如果它可以工作,你应该深入了解自定义会话存储。在我的情况下,set
方法定义错误。当您使用我之前未考过的req.logout()
会话存储destroy()
方法时。而是使用更新的会话调用set
方法。
答案 9 :(得分:0)
这对我有用:
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');
});
确保您的网页不会存储在缓存中
答案 10 :(得分:0)
我遇到了同样的问题。原来我的护照版本与Express 4.0不兼容。只需要安装旧版本。
npm install --save express@3.0.0
答案 11 :(得分:0)
我正在与程序员合作,建议删除req的用户:
app.get('/logout', function (req, res){
req.session.destroy(function (err) {
req.user = null;
res.redirect('/'); //Inside a callback… bulletproof!
});
});
<强>原因:强> 我们需要从req中删除(passportjs也这样做但是异步方式),因为注销后没有使用用户数据 即使这样可以节省内存,也可能是passportjs找到的用户数据,可能会创建新的会话和重定向(但尚未发生) 通过这种方式,我们有责任删除无关紧要的事情。 PassportJS在登录后将数据分配到req.user,如果我们使用req.logout()也会删除它,但它可能无法正常运行,因为NodeJS本质上是异步的
答案 12 :(得分:0)
我遇到了与Passport 0.3.2类似的问题。
当我使用自定义回拨进行护照登录和注册时,问题仍然存在。
通过升级到Passport 0.4.0并添加行
解决了这个问题app.get('/logout', function(req, res) {
req.logOut();
res.redirect('/');
});
答案 13 :(得分:0)
显然,此问题可能有多种原因。在我的情况下,问题是声明的顺序错误,即在护照初始化之前声明了注销终点。正确的顺序是:
app.use(passport.initialize());
app.use(passport.session());
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
答案 14 :(得分:0)
由于您使用的是护照认证,它通过connect.sid
cookie使用它自己的会话,因此最简单的注销方法是让护照处理该会话。
app.get('/logout', function(req, res){
if (req.isAuthenticated()) {
req.logOut()
return res.redirect('/') // Handle valid logout
}
return res.status(401) // Handle unauthenticated response
})
答案 15 :(得分:0)
这里的所有示例都在req.session.destroy之后进行重定向。 但是请务必意识到Express会立即为您重定向到的页面创建一个新会话。 与Postman结合使用时,我发现了一个奇怪的行为,即注销后立即执行Passport登录会产生Passport成功但无法将用户ID存储到会话文件的效果。原因是邮递员需要在该组的所有请求中更新cookie,这需要一段时间。 同样,destroy回调中的重定向也无济于事。
我通过不执行重定向而是返回了json消息来解决了该问题。
答案 16 :(得分:0)
只需添加req.logOut();解决了这个问题; “ O”应大写
答案 17 :(得分:0)
这仍然是个问题。
我所做的是每当他们注销时,在服务器端和客户端使用req.session.destroy(function (err) {});
:
const logout = () => {
const url = '/users/logout'
fetch(url)
setTimeout(function () {
location.reload(); }, 500);
这样,刷新页面时,用户将没有会话。如果没有人通过身份验证,只需确保您重定向到正确的页面即可。
也许不是最好的方法,但是它可行。
答案 18 :(得分:0)
您可以尝试手动重新生成会话:
app.get('/logout', (req, res) => {
req.logOut();
req.session.regenerate(err => {
err && console.log(err);
});
res.redirect('/');
});
这不会从会话中删除其他数据(例如护照)。
答案 19 :(得分:0)
试试这个
app.get('/logout', (req, res) => {
req.logout();
req.session.destroy();
res.redirect('/');
}
答案 20 :(得分:-1)
您应该使用req.logout()破坏浏览器中的会话。
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/'); // whatever the route to your default page is
});
答案 21 :(得分:-3)
我不知道如何解决我的问题ng-href="/signout"
。以前我使用过服务注销,但我直接使用它。
答案 22 :(得分:-3)
在我的情况下,使用传递给req.session.destroy
的回调只在某些时候有所帮助,我不得不求助于这个黑客攻击:
req.session.destroy();
setTimeout(function() {
res.redirect "/";
}, 2000);
我不知道为什么这是我能够开始工作的唯一解决方案,但不幸的是@ JulianLloyd的回答对我来说并不一致。
这可能与我的实时登录页面使用SSL(我无法在登台站点或本地主机上重现该问题)这一事实有关。我的应用程序中可能还有其他内容;我正在使用derby-passport模块,因为我的应用程序正在使用Derby框架,因此很难找出问题所在。
这显然是一个时间问题,因为我首先尝试了超时100毫秒,这还不够。
不幸的是,我还没有找到更好的解决方案。