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

Jef*_*hen 65 javascript logout node.js express passport.js

我无法让我的系统注销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();
}
Run Code Online (Sandbox Code Playgroud)

jlm*_*kes 75

布莱斯的答案很棒,但我仍然注意到了一个重要的区别; Passport指南建议使用.logout()(也有别名.logOut()):

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

但如上所述,这是不可靠的.我发现它在执行Brice的建议时表现得如预期:

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

希望这可以帮助!

  • 请注意,因为在此处给出的示例中,session.destroy的用法假定使用express-sessions模块.其他会话模块(例如,mozilla node-client-sessions)添加了一个仅同步返回的destroy方法,并忽略任何回调参数.在这种情况下,您的代码将挂起 (3认同)
  • 我只是得到'Object#<Session>没有方法'destroy''作为errormessage (2认同)

Bri*_*ice 41

陷入同样的​​问题.使用req.session.destroy();而不是req.logout();工作,但我不知道这是否是最好的做法.

  • 我不喜欢不使用`req.logout()`的想法,为了向前兼容和诸如此类的东西,所以我只是在`req.logout()`之后添加`req.session.destroy();`并且工作正常. (3认同)
  • req.session.destroy(); 也为我工作,记得用res.clearCookie('cookiename')清除你的饼干.但是有谁知道req.logout()究竟是做什么的? (2认同)

esp*_*esp 10

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

这里的问题是,如果您的应用程序也被用作单页面应用程序的API(不推荐但很常见),那么可能会有一些请求由快递处理,在注销之前开始并在注销后结束.如果是这种情况,则此较长时间运行的请求将在删除后以redis还原会话.并且因为下次打开页面时浏览器仍然具有相同的cookie,您将成功登录.

req.session.destroy(function() {
    res.clearCookie('connect.sid');
    res.redirect('/');
});
Run Code Online (Sandbox Code Playgroud)

这就是可能发生的事情:

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

理想情况下,您需要对api调用使用令牌身份验证,并且仅在仅加载页面的Web应用程序中使用会话,但即使您的Web应用程序仅用于获取api令牌,此竞争条件仍然可行.


nrf*_*law 7

我遇到了同样的问题,而且根本不是Passport功能的问题,而是我调用/logout路线的方式.我使用fetch来调用路由:

(坏)

fetch('/auth/logout')
  .then([other stuff]);
Run Code Online (Sandbox Code Playgroud)

结果这样做不会发送cookie所以会话不会继续,我想这些res.logout()获取应用于不同的会话?无论如何,执行以下操作会修复它:

(好)

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


sst*_*oss 6

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

server.get('/logout', (req, res) => {
  req.logout();
  req.session.destroy(()=>{
    res.redirect('/');
  });
});
Run Code Online (Sandbox Code Playgroud)

顺便提一下,我使用 Redis 作为会话存储。


abi*_*ode 5

我有同样的问题,资本O修复了它;

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

  • `logout`和`logOut`在2015年互相别名:https://github.com/jaredhanson/passport/blame/07bff37406241b0cf8db35986788d2dadbf93763/lib/framework/connect.js#L35 (4认同)
  • 当前版本的 Passport 接受注销或注销(与登录和登录相同) (2认同)

Cha*_*ish 5

我最近遇到了同样的问题,但没有一个答案为我解决了这个问题。可能是错误的,但它似乎与竞争条件有关。

将会话详细信息更改为下面的选项似乎已经为我解决了这个问题。我现在已经测试了大约 10 次,一切似乎都正常工作。

app.use(session({
    secret: 'secret',
    saveUninitialized: false,
    resave: false
}));
Run Code Online (Sandbox Code Playgroud)

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

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

app.get('/logout', function(req, res) {
    req.logout();
    res.redirect('/');
});
Run Code Online (Sandbox Code Playgroud)