【问题标题】:req.session.user is deleted while user is activereq.session.user 在用户处于活动状态时被删除
【发布时间】:2018-11-08 09:34:04
【问题描述】:

我将会话超时设置为 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 仍然会增加到期时间,但会删除用户属性。

【问题讨论】:

  • 请发布 redis 选项。我怀疑你设置了数据的过期时间。
  • 我没有在 Redis 上设置任何过期时间。在选项中,我只提供要连接的客户端。此外,即使我遇到超时,会话 id 仍然保留在 redis 中。
  • 只是为了澄清,“遇到超时”,我的意思是我设置的 req.session.user 在 30 分钟仍然处于活动状态后被删除。我在想护照有问题,也许,我不确定。

标签: node.js passport.js node-redis


【解决方案1】:

为什么 req.session.user 在 30 分钟后被删除?

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

会话是您希望在后续请求中保留的一些信息。一般来说,一个会话有一个 ID(sessionID) 和相关的有效载荷。当您执行req.session = { ... } 时,express-session 中间件将获取该对象,生成一个 ID 并将其保存在您指定的 store 中。 (RedisStore 在你的情况下)。所以现在你的“数据库”有sessionIDpayload的映射。

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

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

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


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

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


我将示例代码附加到修补程序。 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");
});

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

我已经更新了代码。

【讨论】:

  • 抱歉,我更糊涂了。我想我了解客户端和服务器之间的会话 cookie 部分。问题是,用户仍然处于活动状态,并且到期时间正在增加。
  • “用户仍然活跃”到底是什么意思?正如我所说,过期时间是 cookie 在该请求中设置的过期时间
  • 因此,无论是否实际设置了 cookie,您总是会看到 expires at = current time + maxAge 。试试看
  • 我的目标是当用户空闲 30 分钟时,会话将过期。因此,当用户尝试调用 api 时,我会抛出一个错误,因为他的会话已经过期。但由于用户仍在 30 分钟内主动调用 api,我预计会话到期会增加。例如,用户已经空闲了 5 分钟,那么距离 session 过期的剩余时间是 25 分钟。然后用户调用一个 api,到期时间重置为 30 分钟。查看 redis 和 req.session,当用户处于活动状态时,它似乎在增加,这是我所期望的。
  • 啊,好吧,现在我理解正确了。我会相应地更新答案,同时,您可能也想用这些细节更新问题!
猜你喜欢
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
相关资源
最近更新 更多