简体   繁体   English

Express session 在每次请求时重置 session

[英]Express session resets session on every request

I have a VueJS project that uses axios to call a server on another domain.我有一个 VueJS 项目,它使用 axios 调用另一个域上的服务器。 On this server, I need to save a few values in the session so they don't need to be looked up on every request.在这台服务器上,我需要在 session 中保存一些值,这样就不需要在每个请求中查找它们。

The server is NodeJS and runs on Heroku and I'm using Redis for memory storage.服务器是 NodeJS,在 Heroku 上运行,我使用 Redis 存储 memory。 I can successfully save data to the session, but on every new request, the system creates a new session with a new ID so I can't access the values saved during the previous request.我可以成功地将数据保存到 session,但是对于每个新请求,系统都会使用新 ID 创建一个新的 session,因此我无法访问在上一个请求期间保存的值。

EDIT After updating the code based on a number of suggestions, I can see the following error in the Network console on the session cookie:编辑根据一些建议更新代码后,我可以在 session cookie 的网络控制台中看到以下错误:

Preflight Invalid Allow Credentials

EDIT 2 I was able to resolve the Preflight Invalid Allow Credentials by adding "credentials: true" to the corsOptions.编辑 2我能够通过向 corsOptions 添加“credentials:true”来解决 Preflight Invalid Allow Credentials。 This resolves the error I was seeing in network on the session, but I am still getting a new session ID for every request.这解决了我在 session 的网络中看到的错误,但我仍然为每个请求获得一个新的 session ID。

Code on the server:服务器上的代码:

const express = require('express');
const app = express();

const cors = require('cors');
var corsWhitelist = ['http://127.0.0.1:8080','http://127.0.0.1:8081']
var corsOptions = {
  origin: function (origin, callback) {
    if (corsWhitelist.indexOf(origin) !== -1) {
        callback(null, true)
    } else {
        callback(new Error('Not allowed by CORS - '+origin))
    }
  },
credentials: true
}

let REDIS_URL = process.env.REDIS_URL;
var Redis = require('ioredis');

const session = require('express-session');
const cookieParser = require('cookie-parser');
const RedisStore = require('connect-redis')(session);
const sessionClient = new Redis(REDIS_URL)

sessionClient.on('error', function (err) {
    console.log('could not establish a connection with redis. ' + err);
  });
sessionClient.on('connect', function (err) {
    console.log('connected to redis successfully');
  });

app.set('trust proxy', 1)
app.use(cookieParser());
app.use(session({
    store: new RedisStore({ client: sessionClient }),
    secret: 'someSecret',
    resave: false,
    saveUninitialized: true,
    cookie: {
        secure: false,
        httpOnly: false,
        maxAge: 1000 * 60 * 10
    }
}))

app.use(cors(corsOptions));
app.options('*', cors(corsOptions))
// Add headers
app.use(function (req, res, next) {
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
        res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
        res.setHeader('Access-Control-Allow-Credentials', 'true');
    }
    next();
});

const getUser = async function(req, res, next) {
    if (!req.session.user) {
        req.session.user = "test@example.com"
        req.session.save()
    }
    next()
  }

app.get('/session', getUser, (req, res) => {
    // get the session id
    console.log('session id:', req.session.id)
    // the session will be automatically stored in Redis with the key prefix 'sess:'
    const sessionKey = `sess:${req.session.id}`;
    // let's see what is in there
    client.get(sessionKey, (err, data) => {
      console.log('session data in redis:', data)
    })
    res.status(200).send('OK');
  })

Method on VueJS: VueJS 上的方法:

getSession: async function () { 
  axios({
    url: 'https://server.example.com/session',
    withCredentials: true,
  }).then(res => {
    console.log(res)
  })
},

There were a number of changes required to make it work:使其工作需要进行许多更改:

The preflight settings were being set twice, so in the code below, I needed to remove the second line:预检设置被设置了两次,所以在下面的代码中,我需要删除第二行:

app.use(cors(corsOptions));
app.options('*', cors(corsOptions)) //delete this

The headers I was trying to set under "// Add headers" didn't make it to the preflight request, so instead I needed to add "credentials: true" to the corsOptions and remove the code under "// Add headers":我试图在“// Add headers”下设置的标头没有进入预检请求,因此我需要将“credentials:true”添加到corsOptions并删除“// Add headers”下的代码:

var corsOptions = {
  origin: function (origin, callback) {
    if (corsWhitelist.indexOf(origin) !== -1) {
        callback(null, true)
    } else {
        callback(new Error('Not allowed by CORS - '+origin))
    }
  },
  credentials: true
}

Last but not least, the cookie settings in the session definition weren't working for a cross-domain request.最后但同样重要的是,session 定义中的 cookie 设置不适用于跨域请求。 Specifically, "sameSite: 'none'" and "secure: true" were necessary.具体来说,“sameSite: 'none'”和“secure: true”是必要的。 Result looks like this:结果如下所示:

app.use(session({
    store: new RedisStore({ client: client }),
    secret: 'someSecret',
    resave: false,
    saveUninitialized: true,
    cookie: {
        secure: true,
        httpOnly: false,
        sameSite: 'none',
        maxAge: 1000 * 60 * 10
    }
}))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM