【问题标题】:Not able to set/receive cookies cross-domain using Netlify and Heroku无法使用 Netlify 和 Heroku 跨域设置/接收 cookie
【发布时间】:2022-04-10 21:05:10
【问题描述】:

由于客户端托管在 Netlify 而服务器托管在 Heroku,我遇到了无法在浏览器中设置 cookie 的问题。它在本地主机上运行良好,所以它似乎与它现在跨域有关。

阅读了多篇关于此的帖子,似乎它可能与 cors 或我如何设置 cookie 开始有关。

我在某处读到,在设置 cookie 时添加 secure: truesameSite: "none" 可能会有所帮助,所以我添加了它们,但没有帮助。我也试过在设置时将domain添加到cookie中,但不幸的是它也没有帮助。

我正在使用 Chrome 并已将设置从使用 icognito 阻止第三方 cookie 更改为允许所有 cookie,因为我已经读到这有时可能是一个问题。然而它也没有产生任何新的结果。

我还读到它可能出于某种原因需要代理,或者可以通过在 Heroku 上托管客户端和服务器来解决。如果可能,我宁愿不必做任何这些事情,但欢迎提出任何想法。

服务器端,在 Heroku 上托管 Node js(express):

const express = require("express");
const app = express();
require("dotenv").config();
const cors = require("cors");
const mysql = require("mysql");
const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");

// port for heroku if needed
const PORT = 3001;

// app objects instantiated on creation of the express server
app.use(
  cors({
    origin: [
      "https://examples.netlify.app",
      "http://localhost:3000",
    ],
    methods: ["GET", "POST", "DELETE"],
    credentials: true,
  })
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());

/*
 * Handel user login
 */
app.post("/sign-in", (req, res) => {
  const { email, password } = req.body;

  sqlSelectAllUsers = "SELECT * FROM user_db WHERE email = ?";
  db.query(sqlSelectAllUsers, [email], (err, user) => {
    if (err) {
      res.send({ err: err });
    }

    if (user && user.length > 0) {
      // given the email check if the password is correct

      bcrypt.compare(password, user[0].password, (err, compareUser) => {
        if (compareUser) {
          //req.session.email = user;
          // create access token
          const accessToken = createAccessToken(user[0]);
          const refreshToken = createRefreshToken(user[0]);
          // create cookie and store it in users browser
          res.cookie("access-token", accessToken, {
            maxAge: 1000 * 60 * 30, // 30 min
            httpOnly: true, // hinder doing document.cookies as it will be httpOnly which will make it more safe
            secure: true,
            domain: "https://examples.netlify.app/",
            sameSite: "none",
          });
          res.cookie("refresh-token", refreshToken, {
            maxAge: 2.63e9, // approx 1 month
            httpOnly: true,
            secure: true,
            domain: "https://examples.netlify.app/",
            sameSite: "none",
          });

          // update refresh token in database
          const sqlUpdateToken =
            "UPDATE user_db SET refresh_token = ? WHERE email = ?";
          db.query(
            sqlUpdateToken,
            [refreshToken, user[0].email],
            (err, result) => {
              if (err) {
                res.send(err);
              }
              res.sendStatus(200);
            }
          );
        } else {
          res.send({ message: "Wrong email or password" });
        }
      });
    } else {
      res.send({ message: "Wrong email or password" });
    }
  });
});

app.listen(process.env.PORT || PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

客户端在 Netlify 上托管 React:

  export default function SignIn() {
  const history = useHistory();

  const handleSubmit = (event) => {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    // eslint-disable-next-line no-console
    axios
      .post(
        "https://example.herokuapp.com/sign-in",
        {
          email: data.get("email"),
          password: data.get("password"),
        },
        { withCredentials: "true" }
      )
      .then((response) => {
        //check if good response then give user a token for valid login
        if (response.data === "OK") {
          history.push("/");
          history.go(0);
        }
      });
  };
}

【问题讨论】:

    标签: node.js reactjs express heroku cookies


    【解决方案1】:

    我不久前遇到了这个问题,简短的回答是: Heroku 不会为域 *.herokuapp.com 设置 cookie,因此如果您的应用程序依赖于 cookie,则无法将 Netlify 或其他主机用于您的前端。这是因为 herokuapp.com 包含在 Mozilla 基金会的公共后缀列表中。

    在代码方面您无能为力。

    如果你想尝试一下,我找到的解决方案(使用 Express 服务器和 Angular 前端)是向 Express 服务器添加一个静态路由/文件夹,我将在其中放置通过构建 Angular 应用程序生成的文件( ng build --configuration production 命令)。当你得到这些文件时,你 git add 它们并使用 Heroku CLI 进行推送。

    通过这样做,Heroku 构建了 Express 服务器,并且您之前使用 Angular CLI 构建的文件都托管在 Heroku dyno 中。这样,cookie 就会被设置,因为它不再是跨域的并且应用程序可以正常工作。

    有关 Heroku 为何阻止此操作的更多信息,请参见其文档的此链接: https://devcenter.heroku.com/articles/cookies-and-herokuapp-com

    编辑:忘了提到我的应用使用了 cookie,因为它实现了 Passport 库的“本地策略”。我没有编写任何代码来处理 cookie,但需要托管能够设置它们以使我的应用程序正常工作。

    【讨论】:

    • 它实际上似乎有效,有点..查看我的答案了解更多信息。
    【解决方案2】:

    可以在以下位置找到解决方案: Cross-Domain Session Cookie (Express API on Heroku + React App on Netlify)

    秘诀是添加 express-session 的会话设置:

        app.use(
          session({
            secret: process.env.SESSION_SECRET || 'Super Secret (change it)',
            resave: true,
            saveUninitialized: false,
            cookie: {
              sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax', // must be 'none' to enable cross-site delivery
              secure: process.env.NODE_ENV === "production", // must be true if sameSite='none'
            }
          })
       );
    

    检查并为我工作!

    【讨论】:

      【解决方案3】:

      好的,所以我终于解决了它,并认为我会在这里写下我是如何做到的。

      尽管似乎是普遍看法,但实际上可以在 Heroku 和 Netlify 之间发送 cookie,有点......

      我认为我在更改设置 cookie 的方式时同时添加了 domainsameSitesecure,因此没有测试没有 domain 的场景。删除 domain 后,可以在 heroku 中设置 cookie,然后使其在 netlify 中工作。所以它可以登录,但是有两个主要问题。 Cookie 会随机停止工作,一旦 Heroku 进入空闲模式(它似乎在免费版本上这样做),它就会弄乱应用程序和 cookie,迫使我重新启动所有测功机。因此,即使通过 Netlify 和 Heroku 似乎可以做到这一点,我也不建议使用 cookie 跨域。 (我还了解到使用sameSite:none 可能会增加 CSRF 攻击的风险,因此不适合在设置 cookie 时使用)

      最终解决方案:我开始在 heroku 上使用代理等在同一个 url 下托管客户端和服务器。这是我遵循的教程的链接,效果很好: https://www.youtube.com/watch?v=xgvLP3f2Y7k&list=LL&index=1&ab_channel=AvanTutor

      现在 cookie 可以正常工作,网站已启动并运行!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-21
        • 2017-03-30
        • 2021-08-29
        • 2021-06-04
        • 1970-01-01
        • 2017-10-06
        • 1970-01-01
        • 2021-02-14
        相关资源
        最近更新 更多