无法使用 Netlify 和 Heroku set/receive cookie 跨域
Not able to set/receive cookies cross-domain using Netlify and Heroku
我有 运行 无法在浏览器中设置 cookie 的问题,因为客户端托管在 Netlify 上,服务器托管在 Heroku 上。它在本地主机上运行良好,因此现在似乎与跨域有关。
阅读了多篇关于此的帖子后,它似乎与 cors 或我如何开始设置 cookie 有关。
我在某处看到它可能有助于在设置 cookie 时添加 secure: true
和 sameSite: "none"
,所以我添加了它们但没有帮助。我也试过在设置cookie时将domain
添加到cookie中,但不幸的是它也没有帮助。
我正在使用 Chrome 并已将设置从使用 icognito 阻止第三方 cookie 更改为允许所有 cookie,因为我了解到这有时可能是一个问题。然而,它也没有产生任何新的结果。
我还读到它可能出于某种原因需要代理,或者可以通过在 Heroku 上同时托管客户端和服务器来解决。如果可能的话,我宁愿不必做任何这些事情,但欢迎任何想法。
服务器端 节点 js (express) 托管在 Heroku 上:
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}`);
});
客户端 React 托管在 Netlify 上:
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);
}
});
};
}
我 运行 不久前进入这个问题,简短的回答是:
Heroku 不会为域 *.herokuapp.com
设置 cookie,因此如果您的应用程序依赖于 cookie,则无法将 Netlify 或其他主机用于您的前端。这是因为 herokuapp.com
包含在 Mozilla 基金会的 Public 后缀列表中。
对此您code-wise无能为力。
如果你想尝试一些东西,我找到的解决方案(使用 Express Server 和 Angular 前端)是向 Express Server 添加一个静态 route/folder ,我会把通过构建 Angular 应用程序(ng build --configuration production
命令)生成的文件。当您获得这些文件时,您 git add
它们并使用 Heroku CLI 进行推送。
通过这样做,Heroku 构建了 Express Server,您之前使用 Angular CLI 构建的文件都托管在 Heroku dyno 中。这样,cookie 就设置好了,因为它不再是 cross-domain 并且应用程序可以正常工作。
有关 Heroku 为什么在其文档 link 中阻止此操作的更多信息:
https://devcenter.heroku.com/articles/cookies-and-herokuapp-com
编辑:忘记提及我的应用程序使用 cookie,因为它实现了 Passport
库的“本地策略”。我没有编写任何代码来处理 cookie,但需要托管才能设置它们以使我的应用程序正常工作。
好吧,我终于解决了它,我想我会在这里写下我是如何做到的。
尽管人们普遍认为,实际上可以在 Heroku 和 Netlify 之间发送 cookie,有点……
我认为我在更改设置 cookie 的方式时同时添加了 domain
、sameSite
和 secure
,因此没有测试没有 [= 的场景10=]。删除 domain
后,可以在 heroku 中设置 cookie,然后使其在 netlify 中工作。所以它可以用于登录,但是这有两个主要问题。 Cookie 会随机停止工作,一旦 Heroku 进入空闲模式(它似乎在免费版本上这样做),它就会弄乱应用程序和 cookie,迫使我重新启动所有测功机。因此,即使通过 Netlify 和 Heroku 似乎可以做到这一点,我也不建议跨域使用 cookie。 (我还读到使用 sameSite:none
可能会增加 CSRF 攻击的风险,因此在设置 cookie 时不适合使用)
最终解决方案: 我开始在相同的 url 下在 heroku 上托管客户端和服务器,使用代理等。这里是 link我遵循的教程,效果很好:
https://www.youtube.com/watch?v=xgvLP3f2Y7k&list=LL&index=1&ab_channel=AvanTutor
现在 cookie 正常工作,网站已启动并且 运行!
可以在以下位置找到解决方案:
秘诀就是添加会话设置 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'
}
})
);
已检查并适用于我!
我有 运行 无法在浏览器中设置 cookie 的问题,因为客户端托管在 Netlify 上,服务器托管在 Heroku 上。它在本地主机上运行良好,因此现在似乎与跨域有关。
阅读了多篇关于此的帖子后,它似乎与 cors 或我如何开始设置 cookie 有关。
我在某处看到它可能有助于在设置 cookie 时添加 secure: true
和 sameSite: "none"
,所以我添加了它们但没有帮助。我也试过在设置cookie时将domain
添加到cookie中,但不幸的是它也没有帮助。
我正在使用 Chrome 并已将设置从使用 icognito 阻止第三方 cookie 更改为允许所有 cookie,因为我了解到这有时可能是一个问题。然而,它也没有产生任何新的结果。
我还读到它可能出于某种原因需要代理,或者可以通过在 Heroku 上同时托管客户端和服务器来解决。如果可能的话,我宁愿不必做任何这些事情,但欢迎任何想法。
服务器端 节点 js (express) 托管在 Heroku 上:
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}`);
});
客户端 React 托管在 Netlify 上:
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);
}
});
};
}
我 运行 不久前进入这个问题,简短的回答是:
Heroku 不会为域 *.herokuapp.com
设置 cookie,因此如果您的应用程序依赖于 cookie,则无法将 Netlify 或其他主机用于您的前端。这是因为 herokuapp.com
包含在 Mozilla 基金会的 Public 后缀列表中。
对此您code-wise无能为力。
如果你想尝试一些东西,我找到的解决方案(使用 Express Server 和 Angular 前端)是向 Express Server 添加一个静态 route/folder ,我会把通过构建 Angular 应用程序(ng build --configuration production
命令)生成的文件。当您获得这些文件时,您 git add
它们并使用 Heroku CLI 进行推送。
通过这样做,Heroku 构建了 Express Server,您之前使用 Angular CLI 构建的文件都托管在 Heroku dyno 中。这样,cookie 就设置好了,因为它不再是 cross-domain 并且应用程序可以正常工作。
有关 Heroku 为什么在其文档 link 中阻止此操作的更多信息: https://devcenter.heroku.com/articles/cookies-and-herokuapp-com
编辑:忘记提及我的应用程序使用 cookie,因为它实现了 Passport
库的“本地策略”。我没有编写任何代码来处理 cookie,但需要托管才能设置它们以使我的应用程序正常工作。
好吧,我终于解决了它,我想我会在这里写下我是如何做到的。
尽管人们普遍认为,实际上可以在 Heroku 和 Netlify 之间发送 cookie,有点……
我认为我在更改设置 cookie 的方式时同时添加了 domain
、sameSite
和 secure
,因此没有测试没有 [= 的场景10=]。删除 domain
后,可以在 heroku 中设置 cookie,然后使其在 netlify 中工作。所以它可以用于登录,但是这有两个主要问题。 Cookie 会随机停止工作,一旦 Heroku 进入空闲模式(它似乎在免费版本上这样做),它就会弄乱应用程序和 cookie,迫使我重新启动所有测功机。因此,即使通过 Netlify 和 Heroku 似乎可以做到这一点,我也不建议跨域使用 cookie。 (我还读到使用 sameSite:none
可能会增加 CSRF 攻击的风险,因此在设置 cookie 时不适合使用)
最终解决方案: 我开始在相同的 url 下在 heroku 上托管客户端和服务器,使用代理等。这里是 link我遵循的教程,效果很好: https://www.youtube.com/watch?v=xgvLP3f2Y7k&list=LL&index=1&ab_channel=AvanTutor
现在 cookie 正常工作,网站已启动并且 运行!
可以在以下位置找到解决方案:
秘诀就是添加会话设置 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'
}
})
);
已检查并适用于我!