Express-session with passport.js multiple cookies

自古美人都是妖i 提交于 2019-12-12 03:27:36

问题


I'm trying to implement the login functionality with passport.js and express-session, it works well,

var passport = require('passport'),
    session = require('express-session'),
    MongoDBStore = require('connect-mongodb-session')(session);

var sessionStore = new MongoDBStore({
    uri: config.db,
    collection: 'sessions'
});

var sessionOptions = {
    name: 'very-secure-cookie',
    secret: config.secret,
    resave: false,
    saveUninitialized: true,
    cookie: {
        secure: true,
        maxAge: null
    },
    store: sessionStore
};

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

Here, maxAge is null, meaning that the client gets logged out when they close the browser window. However, I want to store an additional cookie with the client's email address in order to pre-fill the <input type="text" name="email"> when they want to log back in if they come later.

I've tried app.use()'ing another session object just to store the email information in another cookie, but for some reason the cookie is set only once (the first one).

app.use(session(returningSessionOptions));

Couldn't find any sensible solution anywhere :(

Oh, and I have to mention that I thought about using cookie-parser middleware alongside with express-session, but the docs state that it may result in conflicts.


回答1:


As you didn't include the complete code you used, I assume you set the cookie using res.cookie(name, value[, options]); or res.setHeader('set-cookie', serializedCookie);.

There seems to be an issue with the set-cookie header. When adding multiple cookies, they are appended to the header, separated by comma, which doesn't seem to work in most current browsers. The header is only interpreted until the first comma and therefore only the first cookie is saved. In some browsers everything between the first equals sign and the following semicolon is used as value for that first cookie.

Possible solution

I could reproduce the issue with an old version of Express (3.0.0) using the code below. Using Express 4.13.4 (and also 3.21.2) the same code worked fine. If you are working with an old version of Express, I recommend that you update to the latest one as this should fix the problem. If you are already using a current version, please try if the example works for you. If not, please provide the code and the headers sent by your express-app. In some cases with a more complex application the problem exists even when using versions that work with the example code (I tried Express 3.21.2).

If there is any reason for you not to update to the latest version or the update doesn't fix the issue for you, there is an alternative solution for the problem:

Code to reproduce the issue

To eliminate possible side-effects by other code in the application, here is the minimal example that I used to reproduce your issue:

    var express = require('express');
    var session = require('express-session');
    var passport = require('passport');
    var app = express();

    app.use(session({
        secret: 'keyboard cat',
        resave: false,
        saveUninitialized: true
    }));

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

    app.get('/', function (req, res) {
        res.cookie('cookie', 'value');
      res.send('Hello World!');
    });

    app.listen(3000, function () {
      console.log('Example app listening on port 3000!');
    });

When accessing the express-app (running Express 3.0.x) via the browser, the following response headers are sent:

    set-cookie: cookie=value; Path=/
    set-cookie: cookie=value; Path=/,connect.sid=s%3ARPkxiLfy0dbeBs5eILYBLK6Yh-sOjABS.ykNXCmaOsxtIAXV%2Ba9GCW6YnBi0cBhvZIGvwlj%2F%2Fsy0; Path=/; HttpOnly

Using Express >=3.21.2 everything works fine for this example:

    set-cookie: cookie=value; Path=/
    set-cookie: connect.sid=s%3AR6TVTnUe3eyIvlpT0Hl5ikwcH_XMHXId.ouysyG5tGGekaVDxZMXJP4A8SJfsckLE4GZ3%2B1Eyd1o; Path=/; HttpOnly

Alternative fix

Borrowing the code of function setcookie from express-session for setting your cookies could do the trick for you, as it writes an array containing all the cookies to the header while preserving the ones already added to the response. To do this, install the cookie module, add var cookie = require('cookie'); and replace res.cookie('cookie', 'value'); in the above code with the following lines:

    var data = cookie.serialize('cookie', 'value');
    var prev = res.getHeader('set-cookie') || [];
    var header = Array.isArray(prev) ? prev.concat(data)
      : Array.isArray(data) ? [prev].concat(data)
      : [prev, data];

    res.setHeader('set-cookie', header);

Now the following headers are sent to the browser and all cookies are saved (tested using Google Chrome 49 on MacOS):

    set-cookie:cookie=value
    set-cookie:cookie=value
    set-cookie:connect.sid=s%3Aa1ZPDmERtKwUaPjY__SrPtIrpYC7swQl.0KOs83RSmUTG%2FgPoyOLo4u5UFTjC89yS0Ch0ZVXWVo8; Path=/; HttpOnly

Unfortunately the header is duplicated for the first cookie when using Express 3.0.0, which shouldn't be done according to RFC6265 Section 4.1.1:

Servers SHOULD NOT include more than one Set-Cookie header field in the same response with the same cookie-name. (See Section 5.2 for how user agents handle this case.)

Helpful resources

The following articles may also be helpful:

  • Someone facing a similar problem, but with ASP.NET/Web API instead of node.js/express. However, in my opinion this page provides helpful information on the topic: Set-Cookie Header With Multiple Cookies
  • Another possible solution for setting multiple cookies with node.js/express that might help: http://www.connecto.io/blog/nodejs-express-how-to-set-multiple-cookies-in-the-same-response-object/


来源:https://stackoverflow.com/questions/36112592/express-session-with-passport-js-multiple-cookies

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!