5

我已经设置了一个有效的登录测试,如下所示:

var express = require('express');
var fs = require('fs');
var http = require('http');
var path = require('path');
var routes = require('./routes/index.coffee');
var passport = require('passport');

var LocalStrategy = require('passport-local').Strategy;
var User = require('./userdb.coffee');
var app = express();
var RedisStore = require('connect-redis')(express);

passport.use(new LocalStrategy(function(username, password, done) {
  return User.findOne({
    username: username
  }, function(err, user) {
    if (err) {
      return done(null, false, message: error);
    }
    if (!user) {
      return done(null, false, {
        message: 'Unknown user'
      });
    }
    if (!user.validPassword(password)) {
      return done(null, false, {
        message: 'Invalid password'
      });
    } else {
      return done(null, user);
    }
  });
}));

passport.serializeUser(function(user, done) {
  return done(null, user);
});

passport.deserializeUser(function(user, done) {
  return done(null, user);
});

app.configure(function() {
  app.set('port', process.env.PORT || 5003);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.enable('trust proxy');
  app.use(express["static"](path.join(__dirname, 'public')));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser('SOMESECRET'));
  app.use(express.session({
    cookie: {
      maxAge: 10 * 60 * 1000
    },
    key: 'express.sid',
    secret: 'SOMESECRET',
    store: new RedisStore({
      port: 6379,
      host: 'localhost'
    })
  }));
  app.use(passport.initialize());
  app.use(passport.session());
  return app.use(app.router);
});

var check_auth = function(req, res, next) {
  if (req.isAuthenticated()) {
    console.log(req.session.cookie.expires);
    return next();
  }
  return res.redirect('/login');
};

app.get('/', check_auth, routes.index);
app.get('/login', routes.login);
app.get('/logout', routes.logout);
app.post('/authenticate', passport.authenticate('local', {
  successRedirect: '/',
  failureRedirect: '/login'
}));

app.listen(app.get('port'), '0.0.0.0');

路由和用户逻辑被省略,因为我认为它们与我的问题无关,但如果需要,我会很乐意分享它们(它们非常小,这只是为了获得一个小的概念证明并运行) .

登录工作,阅读会话工作,基于会话值呈现模板工作。 我的问题是 maxAge/expires。我不确定问题出在哪里,但我会尝试描述它:

当我登录时,会话保存passport.js,正确存储在 myRedisStore中,指向会话的 cookie 返回到浏览器。在后续请求中,cookie 被成功找到并指向来自 my 的正确会话SessionStorereq.session.cookie显示更新expires,在我的redis服务器中,TTL 重置为 10 分钟 (600)。

我的问题是 cookie 在浏览器(Chrome、Windows 和 Mac)中保持相同的过期时间。

所以我的问题是:如何进一步调试?随着 req.session 的更新(由express和内部/自动),我想知道问题出在哪里,以及我应该做些什么来解决这个问题:passportCookie保持在初始 maxAges/expiresconnect-redis

非常感谢任何提示、指示或想法。

4

3 回答 3

5

Express-session 支持滚动 cookie 到期日期。不幸的是,它只是最近才被记录下来。

为您的会话使用“滚动”选项。这“强制在每个响应上设置 cookie”并“重置过期日期”。您想将滚动设置为 true。

还要注意“重新保存”选项。“即使在未修改的情况下也强制保存会话......”您可能也希望将该选项设置为 true。请注意,即使此选项的默认值为 true,您也应显式设置该值。现在不推荐使用此选项的默认值,而不是显式设置它。

尝试类似:

app.use( session( { secret: 'keyboard cat',
                    cookie: { maxAge: 60000 },
                    rolling: true,
                    resave: true, 
                    saveUninitialized: false
                  }
         )
);

这是文档。查看“选项”和“options.resave”:https ://github.com/expressjs/session 。

于 2014-12-22T19:39:14.087 回答
1

经过一番挖掘,事实证明 Express 不支持这种滚动,并留给程序员实施作为练习。

如果浏览器的到期时间可以可靠地读取到 ,这将有所帮助express,因此您只能在会话接近到期时触发会话,但我将其用作解决方法(效率低下),直到我想出更聪明的方法:

check_auth = function(req, res, next) {
  console.log(req.isAuthenticated());
  if (req.isAuthenticated()) {
    if (req.session.roll) {
      req.session.roll = 0;
    } else {
      req.session.roll = 1;
    }
    return next();
  }
  return res.redirect('/login');
};

哪里roll可能是任何东西,会话的点被改变了(在每个经过身份验证的请求*上)。

*) 这也意味着它的效率非常低,但现在可以了。

一种替代方法是查找会话 ID 的 TTL。这必须以如下方式进行检查:如果 ttl < 10% * maxAge(由应用程序定义),因为 TTL 实际上在每个请求上都正确更新,只是没有发送 Set-Cookie。因此,假设用户停留在 maxAge 的 90% 以内,他的浏览器 cookie 最终会过期,所以即使这种方法也不够。不过,这可能是一个很好的中间地带。

我将不接受这个问题,以鼓励其他人提出更好的解决方案。

于 2012-10-26T23:58:30.017 回答
0

万一有人在谷歌浏览器中遇到这个问题,解决方案很简单:

app.use(cors({
   allowedHeaders: ['Content-Type','Authorization'],
   origin: '.dev.loc', <- your domain here, but it requires to have a dot infront
   methods:['GET','POST','PUT','DELETE'],
   preflightContinue: true
}));
于 2020-09-02T07:00:39.800 回答