【问题标题】:Express session doesn't persist if the client is on a different domain如果客户端在不同的域中,Express 会话不会持续存在
【发布时间】:2022-01-15 15:10:37
【问题描述】:

tl:dr;

Node (express) 服务器托管在 Heroku 上,而 UI 托管在 Netlify 上。当 UI 对服务器进行 REST API 调用时,会话不会持续存在(但如果我在本地运行两者,它会持续存在。localhost:5000 在服务器上,localhost:3000 在 UI 上。UI 正在使用 package.json 代理请求)。

代码 sn-ps

session.ts

export const sessionConfig = {
  secret: process.env.SESSION_KEY,
  store: new RedisStore({ client: redisClient }),
  resave: true,
  saveUninitialized: true,
  cookie: {
    secure: process.env.NODE_ENV === 'production',
    sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax',
  },
};

server.ts

const app = express();

app.use(express.json());
app.use(cookieParser());

app.set('trust proxy', 1);
app.use(session(sessionConfig)); // This sessionConfig comes from the file above

app.use(cors({
  credentials: true,
  origin: process.env.CLIENT_URL,
}));

我搜索了类似express session not persist when cross domain request 的内容。然后,我看到了像thisthis 这样的线程。似乎app.set('trust proxy', 1) 将确保会话数据将为跨域请求保留。显然,就我而言,仍然缺少一些东西。

有人看到我做错了吗?任何建议将不胜感激!

PS:

我正在使用会话进行验证码测试,看起来像...

captch.ts

CaptchaRouter.get('/api/captcha', async (req: Request, res: Response) => {
  const captcha = CaptchaService.createCaptcha();
  req.session.captchaText = captcha.text;
  res.send(captcha.data);
});

CaptchaRouter.post('/api/captcha', async (req: Request, res: Response) => {
    if (req.session.captchaText !== req.body.captchaText) {
      throw new BadRequestError('Wrong code was provided');
    }

    // The client sent the correct captcha
  },
);

另一个 PS: 下面是响应 heders 的样子:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.netlify.app
Connection: keep-alive
Content-Length: 46
Content-Type: application/json; charset=utf-8
Date: Sun, 09 Jan 2022 00:00:00 GMT
Etag: W/"2e-cds5jiaerjikllkslaxmalmird"
Server: Cowboy
Set-Cookie: connect.sid=s%3ramdon-string-here; Path=/; Expires=Sun, 09 Jan 2022 00:00:00 GMT; HttpOnly; Secure; SameSite=None
Vary: Origin
Via: 1.1 vegur
X-Powered-By: Express

【问题讨论】:

  • 如果您检查 chrome/firefox 开发工具。 AJAX HTTP 请求是返回 200 还是出错?
  • @MattDavis,所有请求都返回200。没有错误(除了会话数据丢失)
  • 如果您在多个请求中注销 req.session.idreq.session.cookie。我假设您为每个请求获得不同的 ID?听起来是两种情况之一:浏览器没有随请求发送 cookie,或者会话没有被持久存储。
  • 也值得注意。如果您使用的是最新版本的express-session,则无需使用app.use(cookieParser())express-session 现在直接从 req/res 对象读取和写入 cookie。使用cookie-parser 也会导致问题。来源:npmjs.com/package/…

标签: node.js express session


【解决方案1】:

原因是客户端(托管在 Netlify 上)没有代理 API 请求。

解决办法是:

  1. 在客户端的public下添加_redirects
/api/*  https://server.herokuapp.com/api/:splat  200

/*  /index.html  200

  1. 确保来自客户端的 API 请求以根 URL 开头
return axios({ method: 'POST', url: '/api/example', headers: defaultHeaders });

为了将来参考,这是我的会话配置

const sessionConfig = {
  secret: process.env.SESSION_KEY || 'This fallback string is necessary for Typescript',
  store: new RedisStore({ client: redisClient }),
  resave: false,
  saveUninitialized: true,
  cookie: {
    secure: process.env.NODE_ENV === 'production', // Prod is supposed to use https
    sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax', // must be 'none' to enable cross-site delivery
    httpOnly: true,
    maxAge: 1000 * 60
  } as { secure: boolean },
};

...这里是server.ts

const app = express();
const port = process.env.PORT || 5000;

app.use(express.json());

app.set('trust proxy', 1);
app.use(session(sessionConfig));

app.use(cors({
  credentials: true,
  origin: process.env.CLIENT_URL,
}));

(正如@Matt Davis 指出的那样,cookieParser 是不必要的)

附言

我没有尝试在会话配置中设置cookie.domain。如果将其设置为客户端 URL(由 Netlify 提供),会话 cookie 是否保留?

【讨论】:

    猜你喜欢
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-03
    • 2023-04-03
    • 2019-05-25
    • 2016-01-20
    • 2020-01-20
    相关资源
    最近更新 更多