admin管理员组

文章数量:1391975

The TLDR is: what would cause a cookie's sessionID to mismatch the sid saved to my database?

I am updating my ExpressJS application from NodeJS 16 to 22, along with all modules I'm using. I use passport, ldapjs, and passport-ldapauth for authentication. That part seems to be working like it used to. It finds the user, grabs AD groups they belong to, and their office location.

What is no longer working is sessions, and populating the req object with the user object, and keeping the same sessionID in the cookie and the database. From what Grok tells me, my passport.deserializeUser routine is what should populate req.user. But by the time it gets there, the sessionID has changed. My deserializer looks in my Session table for a matching sessionID, but because it changes at some point, will no longer find a match. This worked prior to updating everything. I will paste log messages below.

According to Grok, I have made all necessary changes related to passport going from 0.5.2 up to 0.7.0, as well as express-session from 1.17.2 up to 1.18.1. I use sequelize and tedious, both updated to latest. When I remove authentication from endpoints, they run fine and return expected results from my database, so it appears sequelize and such updated just fine.

What is clear, is that the sessionID is changing in a module I did not write, since the log messages indicating it aren't mine. See below which shows messages generated during login. I suspect either passport or express-session. Perhaps there is a new option I am unaware of. I will paste my option objects for both, below the log messages.

This line is in my index.js file and is console.logged between app.use(session(options)) and app.use(passport.initialize()). So we see a sessionID gets generated. It is req.sessionID.

SessionID from cookie: LCQKT6B2-zG_4-_p--X_C93AZhfDGFPe

This is logged immediately after in the same spot, and is req.session.cookie.

Session cookie: { path: '/', _expires: 2025-03-12T23:17:45.376Z, originalMaxAge: 1200000, httpOnly: false, domain:’localhost', sameSite: 'strict', secure: true }

This is logged immediate after the above and is req.session.passport. Of course it is undefined because it hasn't been initialized yet.

Session passport: undefined

app.use(passport.initialize()) is then called, followed by app.use(passport.session()), then passportConfig(passport).

In my passportConfig.js file, I define verifyReqCallback. I believe it is supposed to fire before serializeUser, deserializeUser, and the session model's extDef function. It matches the ID above. This is contained in req.sessionID:

REQ SessionID: LCQKT6B2-zG_4-_p--X_C93AZhfDGFPe

The verifyReqCallback function takes req, user (in my case named userLdap), and done as arguments. I log it to show it is initially undefined, thus. It is userLdap.sessionID.

userLdap.sessionID: undefined

In verifyReqCallback, I then manually set userLdap.sessionID = req.sessionID and log the result, thus:

userLdap.sessionID 2: LCQKT6B2-zG_4-_p--X_C93AZhfDGFPe

This then fires from somewhere.

Executing (default): SELECT [sid], [username], [expires], [data], [createdAt], [updatedAt] FROM [Sessions] AS [Session] WHERE [Session].[sid] = 'LCQKT6B2-zG_4-_p--X_C93AZhfDGFPe';

We then enter my passport.serializeUser function which takes user and done as args...

Calling serializer

At the top, I log user.sessionID. It still matches so far.

SerializeUser sessionID: LCQKT6B2-zG_4-_p--X_C93AZhfDGFPe

In the serializer, I do a Users.findOne which automatically logs this:

Executing (default): SELECT [id], [username], [displayName], [office], [company], [department], [mail], [mobile], [directReports], [active], [createdAt], [updatedAt] FROM [users] AS [user] WHERE [user].[username] = 'myName' AND [user].[active] = 1;

I don't know what runs and logs this line. But we can see the sessionID has changed!!!

Executing (default): SELECT [sid], [username], [expires], [data], [createdAt], [updatedAt] FROM [Sessions] AS [Session] WHERE [Session].[sid] = 'TKCIBtuwD_CxlB2EBTTXkmFrvrdAs1Oc';

And then it inserts it into the database.

Executing (default): INSERT INTO [Sessions] ([sid],[username],[expires],[data],[createdAt],[updatedAt]) OUTPUT INSERTED.[sid],INSERTED.[username],INSERTED.[expires],INSERTED.[data],INSERTED.[createdAt],INSERTED.[updatedAt] VALUES (@0,@1,@2,@3,@4,@5);

However, the passport object of the session, still has the original sessionID. Additionally, the extDef I used to extend the Session table stores the session object in a column I named 'data'. It contains these objects: cookie, passport, rules (I generate permissions from casl), and adLocation.

The stored passport object contains a user object which has the sid in it. Prior to updating everything, this always matched the sid in the table. It no longer matches, as shown above. And since both the session and passport objects have the old sid, looking for a match in the database (in deserializeUser) doesn't work. If I login again (without logging out, using Postman), the 'new' sid becomes the one in the cookie/passport, but a 'newer' one gets put in the DB. So same problem. It never matches as a new one keeps getting generated.

My session options:

let sessParams = {
  secret: process.env.SESSION_SECRET,
  resave: true,// I tried both true and false with no change
  saveUninitialized: true,// not sure if this should be true
  cookie: {
    domain: process.env.ORIGIN_DOMAIN,
    sameSite: 'strict',
    httpOnly: false, // if this isn't set to false, we can't read it via javascript on the client
    maxAge: 1000*60*20, // 20 minutes
    path: '/' // / is the root path of the domain
  },
  store: new store({
    db: seq,
    table: 'Session',
    extendDefaultFields: extDef,
    checkExpirationInterval: 0 //Do not "clean up" expired sessions as that deleted them from the database, which we use as a log.
  }),
  rolling: true, // this allows maxAge to be reset with every request, so it moves with activity
  unset: 'keep' // this is supposed to keep rows in the DB
};

My passport call with options:

passport.use(new LdapStrategy(function (req, callAuth) {
  const domain = 'mycompany'
  callAuth(null, {
    server: {
      url: 'ldap://servernameHere',
      bindDN: `${req.body.username}@${domain}`,
      bindCredentials: `${req.body.password}`,
      searchBase: 'dc=root,dc=mycompany,dc=',
      searchFilter: '(samaccountname={{username}})'
    },
    passReqToCallback: true,
    handleErrorsAsFailures: true,
    failureErrorCallback: function(err) {
      console.log('err callbacky', err)
    },
    failureFlash: true
  })
}, verifyReqCallback))

What else is needed to help figure this out?

本文标签: nodejsExpresssession and passport issuesession ID is changing when it should notStack Overflow