expressjs / session

Simple session middleware for Express
MIT License
6.26k stars 979 forks source link

Can't set manual sessionID #158

Open Jpunt opened 9 years ago

Jpunt commented 9 years ago

Similar to #148, I'm can't seem to set a manual sessionID. Setting it in signedCookies like seems to be the solution doesn't seem to work:

app
  .use(function(req, res, next) {
    if(req.query.sessionID) {
      req.signedCookies["connect.sid"] = req.query.sessionID;
    }
    next();
  })
  .use(session({
    httpOnly: false,
    secret: 'secret',
    resave: false,
    saveUninitialized: true
  })
  .get('/session', function(req, res) {
    console.log('sessionID:', req.sessionID);
    req.session.tmp = req.session.tmp + 1 || 0;
    req.session.save();
    res.send('session: ' + req.session.tmp);
  })

When I hit http://localhost:3000/session?sessionID=42 a couple of times, the counter goes up. When I hit that exact same url in a different browser I expect it to pick up the count from the session, but it does not.

An observation: The log for req.sessionID is not what I gave to the query string, so I guess it's initialising its own sessionID instead.

I've also tried a custom genid like so:

  .use(session({
    httpOnly: false,
    secret: 'secret42',
    resave: false,
    saveUninitialized: true,
    genid: function(req) {
     return req.query.sessionID || uuid.v1();
   }
  })

This seemed like a cleaner solution anyway, but it also doesn't work for me. It sets the sessionID correctly for the first hit, but it won't update it for requests with a different sessionID.

Any help on this would be great!

dougwilson commented 9 years ago

Yes, that work around only works for non-browsers, which do not carry cookies. For this to work in web browsers, you'll need to do a lot of work, sadly, to sign that unsigned value, then form a fake cookie header from it, place it in the right req.headers spot, and remove the incoming value. Otherwise, this module needs to be modified to allow an alternative method besides cookies.

The old express 3 didn't allow for an alternative, either, but it was easier to trick that module (or older versions of this module, which was a copy and paste of express 3).

dougwilson commented 9 years ago

Another workaround could be using the solution from that other issue and also just delete all incoming cookies (if that is an option) by adding "delete req.headers.cookie".

Jpunt commented 9 years ago

Thats too bad.. Deleting req.headers.cookie results in no working sessions at all. Can you point me in the right direction on how to implement the other solution?

dougwilson commented 9 years ago

Deleting req.headers.cookie results in no working sessions at all

Really? It should work, when combined with the workaround of setting req.signedCookies you have above (i.e. do the delete when you set req.signedCookies).

As for the fuller solution, I can see about trying to write it up when I get back to a computer, but really, a PR to allow non-cookie-based sessions would be better in the long run.

dougwilson commented 9 years ago

Essentially we don't officially support non-cookie-based sessions until there is a PR offered up that works well and is accepted.

Jpunt commented 9 years ago

To avoid any mixups, this is what i've tried:

app
  .use(function(req, res, next) {
    if(req.query.sessionID) {
      req.signedCookies["connect.sid"] = req.query.sessionID;
      delete req.headers.cookie;
    }
    next();
  })
  .use(session({
    httpOnly: false,
    secret: 'secret',
    resave: false,
    saveUninitialized: true
  })
  .get('/session', function(req, res) {
    console.log('sessionID:', req.sessionID);
    req.session.tmp = req.session.tmp + 1 || 0;
    req.session.save();
    res.send('session: ' + req.session.tmp);
  })

I agree that a non-cookie-option in the module would be a better solution. I'll investigate what needs to be done in the next couple days.

Jpunt commented 9 years ago

This option turned out to be pretty easy to implement, but I don't have a huge amount of experience in express-middlewares. Can you take a look and see if it makes any sense?

https://github.com/expressjs/session/compare/cda52fcdac4c84f6c54d161e0380fe5fbb9b93ae...Jpunt:master

If so, I'll make some tests and a PR :)

dougwilson commented 9 years ago

Just go ahead and make the PR right away :) I can comment on it and we can always iterate!

Jpunt commented 9 years ago

Alright! :metal:

weepy commented 8 years ago

This was a real life saver. Can this be merged onto master ?

jacoscaz commented 8 years ago

Agreed. When can we expect this to be merged into master?

mgttt commented 6 years ago

really need to set the manual sessionID

knoxcard commented 6 years ago

emergency emergence emerge merger merger ... merge

em92 commented 6 years ago

Middleware configuration:

const uid = require("uid-safe").sync;

var middleware = session({
  genid: function(req) {
    if ( (req.session) && (req.session.uid) ) {
      return req.session.uid + "_" + uid(24);
    } else {
      return uid(24);
    }
  }
  secret: config.cookieSecret,
  store: sessionStore,
  resave: false,
  saveUninitialized: false
})

On successfull authentification:

req.session.uid = data.id;
req.session.regenerate(function (err) {
  if (err) throw err;
  req.session.uid = data.id;
  // ...
});
knoxcard commented 6 years ago

@em92 - Clever... Thanks!

cuongtavan commented 5 years ago

Simply remove cookie/headers by creating a middleware for route, and run before session middleware -> this help express-session alway run to genid function

function makeid(length) {
  var result           = '';
  var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  var charactersLength = characters.length;
  for ( var i = 0; i < length; i++ ) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}
  let app = express();
  app.use('/test', (req, res, next) => {
    console.log("Delete cookie, header values:", req.headers);
    delete req.cookies;
    delete req.headers['cookie'];
    next();
  })
  app.use(session({
    genid: function(req) {
      console.log('Run to genid function', req.query);
      if (req.query.ssId) {
        return req.query.ssId;
      } else {
        return makeid(12);
      }
    },
    resave: false,
    saveUninitialized: false
  }));

  const router = express.Router()

  router.use('/test', (req, res, next) => {
    req.session.user_data={name: "cuong ta"};
    res.json({
      receive: true,
      sessionId: req.sessionID
    });
  })

Test with http://localhost/test?ssId=123456

sgpinkus commented 4 years ago

Need this too: I.e. allow to customise the way a request is associated with its session, as opposed to hard coded dependency on sid-cookie.

@em92 genid does not appear to be a solution. In will not re-associate the req with an existing session. The SID changes but the existing session data is lost in my testing.