将 express-session 生成的 session ID cookie 发送到 different-origin React 前端

Send an express-session generated session ID cookie to a different-origin React front end

我正在制作一个网络应用程序。我的后端使用 Node.js、Express.js,具体来说,它使用模块 express-session 为 session-based authentication 创建一个 session object,以便坚持用户登录。我了解到,当我使用express-session 创建一个session 时,会在后端创建一个ID 为session 的cookie,并发送到前端的浏览器。当我使用我的浏览器并访问托管 Express 应用程序的页面(在我的例子中,localhost:3001)时,我已验证此 cookie 会无缝发送。

// My Express app's index.js file
// This code seamlessly sends a session ID cookie to the browser when I visit http://localhost:3001

const express = require('express');
const session = require('express-session');
const mongoDbStore = require('connect-mongodb-session')(session);
const app = express();
const store = new mongoDbStore({
    uri: 'mongodb://localhost:27017/GameDB',
    collection: 'UserSessions'
});

store.on('error', (err) => {
    console.log('Something exploded:' + err);
});

app.use(session({
    secret: 'I am stuck, help me please!',
    store: store,
    saveUninitialized: true,
    resave: false,
} ));

app.listen(3001, () => {
    console.log('server started on 3001');
})

而且我的饼干很好吃。这是我的 Chrome 开发人员工具中的屏幕截图:

但是,我希望我的前端是一个单独的应用程序(我正在使用 React),并且我想使用来自前端的 API 请求来访问我后端的所有内容。由于前端和后端是独立的应用程序,因此它们需要 运行 在不同的端口上。我的前端将 运行 连接到端口 3000,我的后端将继续连接到端口 3001 上的 运行。考虑到这一点,我将 运行ning localhost:3000我的浏览器而不是 localhost:3001.

唯一的问题是,通过这些更改,express-session 制作的 cookie 不再发送到我的浏览器,即使我执行 HTTP POST(通过 JavaScript fetch()) 从我的前端到我的后端并得到一个有效的响应。

简而言之,我的问题是:当我在前端使用单独的应用程序时,如何将我的 express-session session ID cookie 保存到我的浏览器结束?

这是我的前端API请求:

fetch('http://localhost:3001/gimmecookie', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
    },
    body: JSON.stringify({ data: "data" })
})
.then(response => response.json() )
.then(response => {
    console.log(response)
})
.catch((error) => {
    console.error(error);
});

这是我的 Express 应用程序的 slightly-modified-from-before index.js 文件:

// My Express app's index.js file that *should* create and 
//   send a session-id cookie to my React project

const express = require('express');
const cors = require('cors');
const session = require('express-session');
const mongoDbStore = require('connect-mongodb-session')(session);
const app = express();

const corsOptions = {
    origin: 'http://localhost:3000',
}

const store = new mongoDbStore({
    uri: 'mongodb://localhost:27017/GameDB',
    collection: 'UserSessions'
});

store.on('error', (err) => {
    console.log('Something exploded:' + err);
});

app.use(cors(corsOptions));

app.use(session({
    secret: 'I am stuck, help me please!',
    store: store,
    saveUninitialized: true,
    resave: false,
}));

app.post('/gimmecookie', (req, res) => {
    res.json({ sendsome: "data" })
});

app.listen(3001, () => {
    console.log('server started on 3001');
});

现在,我正在使用 hack 来发送 cookie(在 JS 中创建一个 cookie 并手动发送它),但是随着我的项目越来越大,hack 越来越烦人。我需要在此代码中添加什么才能像我只使用一个应用程序时那样发送 cookie? express-session 不是为此设计的吗? (似乎是这样,我知道前端和后端都有一个单独的应用程序是非常普遍的。)

如果前端和后端有任何形式的握手,我是否应该期望 cookie 自动发送?我需要在 express-session 初始化 object 中弄乱 cookie.domaincookie.sameSite 属性吗?我需要搞乱 CORS 或 fetch() Accept header 吗? res.json() 是不是用错了方法?处理真实 IP 而不是 localhost 更容易吗?我已经尝试了很多东西,但无论我做什么,我都无法在我的浏览器上得到爆炸 express-session 生成的 session ID cookie。

原来是前端的问题,不是后端的问题,是CORS的问题。快速会话代码使 cookie 正常,但前端无法接受它,因为后端托管在端口 3001 上使其成为跨源请求(您会记得前端在端口 3000 上) ,即使前后端都在同一台机器上,localhost.

我所要做的就是在我的 React 项目中使用 package.json 文件中的 proxy 字段,就像这样:

    ...
  },
  "proxy": "http://localhost:3001"
}

随着代理更改,我还必须更改我的 React 代码中的 fetch(),从此:

fetch('http://localhost:3001/gimmecookie', {
  ...

对此:

fetch('/gimmecookie', {
  ...

因为我的 proxy 字段欺骗了我的 React 项目,让我认为我在不同端口上的后端实际上是同源的。

旁注:一旦我意识到这是一个前端 CORS 问题,我就尝试了一些其他解决方案(例如在 [=14] 中使用 credentials: include =] init object),但很快就发现这些解决方案有很大的缺点,直到我找到了代理解决方案。 Flippn' CORS!