req.session.user 在用户处于活动状态时被删除

req.session.user is deleted while user is active

我将会话超时设置为 30 分钟。当我仍然活跃时,req.session.user 会在 30 分钟后被删除。但是,会话仍然存在。这是我的配置(我正在使用 express-session 和 passport.js):

app.use(session({
    store: new RedisStore({client: <my client>, disableTTL: true}),
    secret: <some_secret>,
    resave: true,
    saveUninitialized: false,
    cookie: {maxAge: 1800000}
}));

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

// Are these serializer/deserializer needed?
passport.serializeUser((user, done) => {
    done(null, user);
});
passport.deserializeUser((user, done) => {
    done(null, user);
});

登录中:

router.post('/login', (req, res, next) => {
    passport.authenticate('ldapauth', {session: false}, (err, user, info) => {
        ...
        if (user) {
            req.session.user = {email: req.body.username};
        }
        next();
    })(req, res);
});

验证码是这样的:

isLoggedIn() {
    if (req.session && req.session.user) {
        return true;
    }
    return false;
}

我在成功登录后将 req.session.user 设置为某个对象。

因此,30 分钟后,req.session.user 被删除,但 req.session 仍然存在,并且由于我仍在积极处理该页面,因此不断增加到期日期。

为什么 req.session.user 在 30 分钟后被删除?我以为护照是坐快车上课的?

* 更新 * 起初,我以为到期时间是递增的,但事实并非如此。以前,我设置 resave: false。然后当我登录会话时,到期时间总是相同的:

Session {
    cookie:
         { path: '/', _expires: <some date>.... }
    user:
         { email: <the one i set before>, sessionId: <some id> } }

然后 30 分钟后,用户被删除。只有在这一点上,到期时间才开始递增。

Session {
    cookie:
         { path: '/', _expires: <some date>.... }

然后我阅读了一些有关 express-session 调用的 touch 方法的内容。文档说如果store实现了这个touch方法,那么设置resave: false就可以了。所以,想到redis可能没有实现这个方法,我尝试设置resave: true。然后,当我记录会话时,我注意到到期时间现在正在增加,而之前它只在用户被删除后才增加。然而,30 分钟后,用户密钥再次被删除。

然后在niry的建议下,我设置了disableTTL: true。同样的事情又发生了。

在redis中,我尝试获取密钥。在 30 分钟结束之前,redis 中的到期时间递增:

127.0.0.1:6379> mget sess:<some id>

1) "{\"cookie\":{\"originalMaxAge\":1800000,\"expires\":\"2018-11-15T06:04:26.994Z\",\"httpOnly\":true,\"path\":\"/\"},\"user\":{\"email\":\"test@email.com\",\"sessionId\": \"some session id\"}}"

然后 30 分钟后,我查看了 redis,会话密钥仍然存在,但它停止递增到期时间。同时,req.session 仍会增加​​到期时间,但会删除用户 属性。

Why is req.session.user deleted after 30 minutes?

因为cookie的maxAge选项设置为1800000毫秒,也就是30分钟。因此浏览器(或您使用的任何客户端)将在 30 分钟后删除 cookie。

会话是您希望在后续请求中保留的一些信息。通常,一个会话有一个 ID(sessionID) 和关联的负载。当您执行 req.session = { ... } 时,express-session 中间件将获取对象,生成一个 ID 并将其保存在您指定的 store 中。 (RedisStore 在你的情况下)。所以现在你的 "database" 有 sessionIDpayload 的映射。

Cookie 是一旦从服务器发送的东西,每次后续请求都会将它们转发到该服务器(到该域),直到它们过期。请注意,一旦收到 cookie,管理它就是客户端的工作。生成的 sessionID 连同签名一起发送到 cookie 中的客户端。

一旦 cookie 保存在您的客户端上。它将与下一个请求一起转发。 当您的 express-session 中间件看到 cookie 时,它​​会从 cookie 中提取 sessionID,并尝试在 store 中查找相应的负载(在您的情况下为 RedisStore)。然后将有效负载与其他信息一起设置为 req.session

一旦达到过期时间,客户端将删除cookie。因此,来自该客户端的请求不会有 cookie。因为 cookie 不存在,express-session 将无法设置 req.session,您会认为用户已注销。请注意,商店仍然包含 sessionID, payload 映射,它将根据 store.

ttl 配置被删除

我认为首先出现的混乱是因为 session.cookie 字段。由于 express-session 中间件,session.cookie 将始终存在。

如果您想查看请求中收到的实际 cookie,请尝试 cookie-parser 中间件。


我正在将示例代码附加到 tinker。 set-cookie 端点将设置 20 秒后过期的 cookie。 get-cookie 端点将获得 cookiesession 数据。

希望这会有所帮助!

const express = require("express");
const session = require("express-session");
const cookieParser = require("cookie-parser");
const FileStore = require("session-file-store")(session);
const path = require("path");

const app = express();

app.use(express.json());

app.use(cookieParser());
app.use(
    session({
        secret: "top secret!",
        resave: false,
        rolling: true,
        saveUninitialized: false,
        cookie: {
            maxAge: 20 * 1000
        },
        name: "demo",
        store: new FileStore({
            path: path.join(__dirname, "../sessions"),
            retries: 1,
            fileExtension: ".json"
        })
    })
);

app.use("/set-cookie", (req, res) => {
    req.session.payload = { foo: "bar", timestamp: new Date().toISOString() };
    res.json({ message: "done" });
});

app.use("/get-cookie", (req, res) => {
    res.json({
        sessionID: req.sessionID,
        session: req.session,
        cookies: req.cookies,
        timestamp: new Date().toISOString()
    });
});

app.listen(3000, err => {
    if (err) {
        throw err;
    }
    console.log("demo app listening on port 3000");
});

更新 根据评论,您正在寻找 rolling 选项。在 express-session 中设置 rolling: true 后,会话将为每个请求更新。并且用户将在 maxAge 理想时间后注销。

我更新了代码。