如何使用connect mongo更新请求之外的快速会话?

问题描述

我正在构建与 Express Session 的集成,并且我正在尝试在单独的 Webhook 中对用户进行身份验证。所以我需要一种方法来更新请求之外的用户会话,因为这将是一个不同的请求。

我所做的是将会话 ID 传递给新请求,并使用 MongoClient 更新数据库中的会话。我记得 Express Session 只在客户端存储 ID,数据存储在数据库中,所以我假设更新数据库可以做到。但情况似乎并非如此。我可以清楚地看到 MongoDB 上的会话已全部更新,但我一直在 req.session.data获取过时的数据。

这是我所做的

所以我尝试的第一件事是使用 req.session.reload() 方法,如下所示:

Updating express-session sessions

change and refresh session data in Node.js and express-session

但它仍然给我过时的数据,好像该函数什么也没做(它确实打印了日志,所以我认为它确实运行了)。

我尝试使用它使用 Express Session 中的 store.get() 方法,但它给了我 undefined 会话。

Express load Session from Mongo with session_id

所以作为最后的手段,我使用 MongoClient 直接获取会话数据并使用获取的数据更新会话。我使用 async 作为路由处理程序并等待 MongoClient 获取数据。它不等待等待,只是不断抛出 undefined。我认为是我的代码有问题,但我能够使用代码获取用户数据,并且它确实等待 MongoClient 获取数据,但不知何故它不适用于会话数据。

这是我的部分代码

app.router.get('/login',async function (req,res,next) {
  req.session.auth = await mongo.getCookie(req.session.id).auth;
  req.session.user = await mongo.getCookie(req.session.id).user;
  console.log('Login Action',req.session.id,req.session.auth,req.session.user);
}
module.exports.getCookie = async function getCookie(identifier) {
  try {
    let database = client.db('database');
    let collection = await database.collection('sessions');
    let result = await collection.findOne({ _id: identifier },function(err,res) {
      if (err) throw err;
      return res;
    });
    return result;
  }
  catch (err) {
    console.error(err);
    return null;
  }
}

这是我检查过的其他答案

这个只更新过期时间,所以我认为它不会为我工作,我确实将重新保存设置为 false 以便它不会尝试保存每个请求,因为它保存到数据库我认为它有与更新无关,我尝试将其设置为 true,但什么也没发生。

Renewing/Refreshing Express Session

在这个过程中它使用了 socket.io 和 store.get(),所以它不会正常工作。

How to access session in express,outside of the req?

有人可以指导我如何让 Express Session 从数据库中更新,或者有没有办法从数据库获取数据并以这种方式更新会话?

解决方法

所以我最终弄明白了,结果会话没有从数据库更新。看起来它在缓存中有一个本地副本,但我的印象是快速会话只使用数据库。

我知道我的数据确实在数据库中,但不在缓存中,也不在存储快速会话的本地副本的任何地方。所以解决这个问题最简单的方法就是用数据库上的数据更新本地副本。

我创建了这个函数来更新会话数据

async function sessionUpdate(req) {
  try {
    // get the data on the database
    let tempSession = await mongo.getCookie(req.session.id);

    // if the data exist,we can copy that to our current session
    if (tempSession) {
      req.session.auth = tempSession.auth;
      req.session.user = tempSession.user;
      
      // you can do other stuff that you need to do with the data too
      if (req.session.health == null || req.session.health == undefined || typeof req.session.health === 'undefined') {
        req.session.health = 0;
      }

      // This update and save the data to the session
      req.session.save( function(err) {
        req.session.reload( function (err) {
          //console.log('Session Updated');
        });
      });
    }
    else if (!tempSession) {
      req.session.auth = false;
      req.session.user = null;
      req.session.ip = request.connection.remoteAddress;
    }
  }
  catch (err) {
    console.error(err);
  }
}

现在我们有了一个可以更新会话数据的函数,我们需要在任何地方实现它。我使用中间件来做到这一点,你也可以使用其他方法,但必须在路由或会话逻辑之前调用。

// middleware with no mounted path so it is used for all requests
receiver.router.use(async function (req,res,next) {
  try {
    await sessionUpdate(req);
  }
  catch (err) {
    console.error(err);
  }
  next();
});

这不是一个好的/有效的方法......甚至在到达路线之前要运行很多东西,所以我认为它会降低性能......但这就是我的方式让它工作,如果有人能想出更好的主意,我将不胜感激?