快速会话不会注销

Posted

技术标签:

【中文标题】快速会话不会注销【英文标题】:express-session won't log out 【发布时间】:2014-12-21 18:51:06 【问题描述】:

代码

app.js:

var express = require('express');
var session = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
var passport = require('passport');

var config = require('./config');
var routes = require('./routes');

var mongodb = mongoose.connect(config.mongodb);

var app = express();

// view engine setup
app.set('views', config.root + '/views');
app.set('view engine', 'jade');
app.engine('html', require('ejs').renderFile);

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded(
  extended: false
));
app.use(cookieParser());
app.use(express.static(config.root + '/public'));

app.use(session(
  name: 'myCookie',
  secret: 'tehSecret',
  resave: true,
  saveUninitialized: true,
  unset: 'destroy',
  store: new mongoStore(
    db: mongodb.connection.db,
    collection: 'sessions'
  )
));

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

app.use('/', routes);

app.set('port', config.port);

var server = app.listen(app.get('port'), function() 
  if (config.debug) 
    debug('Express server listening on port ' + server.address().port);
  
);

routes.js:

var express = require('express');
var router = express.Router();

var config = require('../config');
var userController = require('../controllers/user');
var authController = require('../controllers/auth');

router.get('/', function(req, res) 
  res.render('index', 
    title: config.app.name
  );
);

router.route('/users')
  .post(userController.postUsers)
  .get(authController.isAuthenticated, userController.getUsers);
router.get('/signout', userController.signout);

module.exports = router;

模型/user.js:

var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');

var UserSchema = new mongoose.Schema(
  username: 
    type: String,
    unique: true,
    required: true
  ,
  password: 
    type: String,
    required: true
  
);

// Execute before each user.save() call
UserSchema.pre('save', function(callback) 
  var user = this;

  // Break out if the password hasn't changed
  if (!user.isModified('password')) return callback();

  // Password changed so we need to hash it
  bcrypt.genSalt(5, function(err, salt) 
    if (err) return callback(err);

    bcrypt.hash(user.password, salt, null, function(err, hash) 
      if (err) return callback(err);
      user.password = hash;
      callback();
    );
  );
);

UserSchema.methods.verifyPassword = function(password, cb) 
  bcrypt.compare(password, this.password, function(err, isMatch) 
    if (err) return cb(err);
    cb(null, isMatch);
  );
;

// Export the Mongoose model
module.exports = mongoose.model('User', UserSchema);

控制器/user.js:

var config = require('../config');

var User = require('../models/user');

exports.postUsers = function(req, res) 
  if (config.debug)
    console.log("user.postUsers()");

  var user = new User(
    username: req.body.username,
    password: req.body.password
  );

  user.save(function(err) 
    if (err)
      return res.send(err);

    if (config.debug)
      console.log("saved");

    res.json(
      message: 'New user created!'
    );
  );
;

exports.getUsers = function(req, res) 
  if (config.debug)
    console.log("user.getUsers()");

  User.find(function(err, users) 
    if (err)
      return res.send(err);

    if (config.debug)
      console.log("users", users);

    res.json(users);
  );
;

exports.signout = function(req, res) 
  if (config.debug)
    console.log("user.signout()");

  res.clearCookie('myCookie');

  req.session.destroy(function(err) 
    req.logout();
    res.redirect('/');
  );
;

控制器/auth.js:

var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;

var config = require('../config');
var User = require('../models/user');

passport.serializeUser(function(user, done) 
  done(null, user.id);
);

passport.deserializeUser(function(id, done) 
  User.findById(id, function(err, user) 
    done(err, user);
  );
);

passport.use(new BasicStrategy(
  function(username, password, done) 
    User.findOne(
      username: username
    , function(err, user) 
      if (err) 
        return done(err);
      

      // No user found with that username
      if (!user) 
        return done(null, false);
      

      // Make sure the password is correct
      user.verifyPassword(password, function(err, isMatch) 
        if (err) 
          return done(err);
        

        // Password did not match
        if (!isMatch) 
          return done(null, false);
        

        // Success
        return done(null, user);
      );
    );
  
));

exports.isAuthenticated = passport.authenticate('basic', 
  session: false
);

问题

/signout 路由不会结束当前会话。在 req.session.destroy 回调中,req.sessionundefined,但对 /users 的新 GET 请求就像会话有效一样。

有人可以帮忙解决这个问题吗?

【问题讨论】:

不登录也能访问 /users 吗? @JasonNichols 不。基本身份验证被触发。但是,一旦我登录,我就无法退出。 您能在您的路线中使用 console.log(req.user) 吗?顺便说一句。 afaik 在您的序列化用户中它实际上应该是 user._id,因为 mongodb 默认使用 _id 而不是 id。 我认为你不能轻易注销基本身份验证,请参阅***.com/questions/233507/… @cschaeffler req.user 未定义。我还添加了authController.isAuthenticated 到 /signout 路由,现在req.user 是当前登录的用户对象。但是,不会执行注销。 【参考方案1】:

如果像我一样,您是因为问题标题而不是详细信息而来到这里的 - 答案是 req.session.destroy()。我认为注销功能是 passport.js 特有的,如果您使用标准 express-session,它将无法工作。

【讨论】:

【参考方案2】:

解决方案

控制器/user.js:

exports.signout = function(req, res) 
  if (config.debug)
    console.log("user.signout()");

  req.logout();
  res.send(401);
;

顺便说一句。不要介意注销后会话仍在数据库中。 Mongod 在 60 秒后检查并清除它们。

【讨论】:

【参考方案3】:

在不使用 req.session.destroy() 的情况下登录 api 尝试 req.logout();。我希望它会起作用。

【讨论】:

对不起,这也没有用。 (这是我在尝试destroy 之前的第一种方法)。

以上是关于快速会话不会注销的主要内容,如果未能解决你的问题,请参考以下文章

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

快速单击链接会导致注销(会话锁定?)

注销时不会放弃会话

Keycloak 注销不会结束会话

phpmyadmin sso 不会在注销时删除现有会话

会话验证过滤器在会话过期时注销用户