Laravel 7 Sanctum:相同的域 (*.herokuapp.com) 但单独的 React SPA 获取 CSRF 令牌不匹配
Laravel 7 Sanctum: Same domain (*.herokuapp.com) but separate React SPA gets CSRF Token Mismatch
我从这个论坛上读了很多书,也看了很多关于 如何使用 Sanctum 将单独的 React/Vue SPA 连接到 Laravel API 的教程视频Auth 但 none 的解决方案对我有用。这是我的学校项目。
这就是我到目前为止所做的。
我创建了 2 个文件夹,一个用于 api,一个用于前端。我在 api 文件夹中安装了 Laravel,并在 frontend 文件夹中安装了 React 应用程序。这两个都已 Git 初始化并拥有自己的 Git 集线器存储库。此外,它们都部署到 Heroku。
API
Repository: https://github.com/luchmewep/jarcalc_api
Website: https://jarcalc-api.herokuapp.com
前端
Repository: https://github.com/luchmewep/jarcalc_front
Website: https://jarcalculator.herokuapp.com
在本地,一切运行都很好。我可以将错误消息设置为前端的电子邮件和密码字段,这意味着我已经收到并发送了 laravel_session 和 XSRF_TOKEN饼干。我还在虚拟仪表板上显示了经过身份验证的用户的信息,因此 在本地.
上一切正常
在互联网上,我的两个应用程序 运行 但不会相互通信。在官方文档中,它们必须至少在 同一域 上,在这种情况下,它们是同一域的子域,即 .herokuapp.com.
这是每个 Heroku 应用程序的环境变量。
API
SANCTUM_STATEFUL_DOMAINS = jarcalculator.herokuapp.com
(I've tried adding "SESSION_DRIVER=cookie" and "SESSION_DOMAIN=.herokuapp.com" but still not working!)
更新
发现 axios 在尝试 POST 请求 /login 时没有携带 XSRF-TOKEN。自动进行本地测试。
相关代码如下:
api.tsx
import axios from "axios";
export default axios.create({
baseURL: `${process.env.REACT_APP_API_URL}`,
withCredentials: true,
});
Login.tsx
...
const handleSubmit = (e: any) => {
e.preventDefault();
let login = { email: email.value, password: password.value };
api.get("/sanctum/csrf-cookie").then((res) => {
api.post("/login", login).then((res) => {
/**
* goes here if login succeeds...
*/
console.log("Login Success");
...
})
.catch((e) => {
console.log("Login failed...")
});
})
.catch((e) => {
console.log("CSRF failed...");
});
};
更新
".herokuapp.com is included in the Mozilla Foundation’s Public Suffix List. This list is used in recent versions of several browsers, such as Firefox, Chrome and Opera, to limit how broadly a cookie may be scoped. In other words, in browsers that support the functionality, applications in the herokuapp.com domain are prevented from setting cookies for *.herokuapp.com."
https://devcenter.heroku.com/articles/cookies-and-herokuapp-com
本地 COOKIES
已部署 COOKIES
解释:虽然 API 和前端都有 .herokuapp.com,但这并不会使它们 在同一个域上。它在上面的 Heroku 文章中有解释。这意味着 *.herokuapp.com 之间的所有请求都被视为 cross-site 而不是 same-site.
解决方案
由于axios携带了laravel_sessioncookie,所以只剩下xsrf-tokencookie的问题了。要解决这个问题,必须购买一个域名,并为每个域名设置子域名。就我而言,我的 React 前端现在位于 www.jarcalculator.me while my Laravel backend is now at api.jarcalculator.me。由于它们现在是同一站点,无论它们部署在哪里(React 移至 Git 中心页面,而 Laravel 在 Heroku),可以自动设置 cookie。
通过 Github Student Pack 申请我的免费域名,终于解决了我的问题。我将我的 React 应用程序的域名设置为 www.jarcalculator.me,同时将我的 Laravel 应用程序的域名设置为 api.jarcalculator.me。由于它们现在是同一域 jarcalculator.me 的子域,包含 CSRF 令牌和 laravel_session 令牌的 cookie 的传递是 自动 。无需修改 axios 设置。只需将 axios 的 withCredentials 设置为 true 即可。
我从这个论坛上读了很多书,也看了很多关于 如何使用 Sanctum 将单独的 React/Vue SPA 连接到 Laravel API 的教程视频Auth 但 none 的解决方案对我有用。这是我的学校项目。
这就是我到目前为止所做的。
我创建了 2 个文件夹,一个用于 api,一个用于前端。我在 api 文件夹中安装了 Laravel,并在 frontend 文件夹中安装了 React 应用程序。这两个都已 Git 初始化并拥有自己的 Git 集线器存储库。此外,它们都部署到 Heroku。
API
Repository:
https://github.com/luchmewep/jarcalc_api
Website:
https://jarcalc-api.herokuapp.com
前端
Repository:
https://github.com/luchmewep/jarcalc_front
Website:
https://jarcalculator.herokuapp.com
在本地,一切运行都很好。我可以将错误消息设置为前端的电子邮件和密码字段,这意味着我已经收到并发送了 laravel_session 和 XSRF_TOKEN饼干。我还在虚拟仪表板上显示了经过身份验证的用户的信息,因此 在本地.
上一切正常在互联网上,我的两个应用程序 运行 但不会相互通信。在官方文档中,它们必须至少在 同一域 上,在这种情况下,它们是同一域的子域,即 .herokuapp.com.
这是每个 Heroku 应用程序的环境变量。
API
SANCTUM_STATEFUL_DOMAINS = jarcalculator.herokuapp.com
(I've tried adding "SESSION_DRIVER=cookie" and "SESSION_DOMAIN=.herokuapp.com" but still not working!)
更新
发现 axios 在尝试 POST 请求 /login 时没有携带 XSRF-TOKEN。自动进行本地测试。
相关代码如下:
api.tsx
import axios from "axios";
export default axios.create({
baseURL: `${process.env.REACT_APP_API_URL}`,
withCredentials: true,
});
Login.tsx
...
const handleSubmit = (e: any) => {
e.preventDefault();
let login = { email: email.value, password: password.value };
api.get("/sanctum/csrf-cookie").then((res) => {
api.post("/login", login).then((res) => {
/**
* goes here if login succeeds...
*/
console.log("Login Success");
...
})
.catch((e) => {
console.log("Login failed...")
});
})
.catch((e) => {
console.log("CSRF failed...");
});
};
更新
".herokuapp.com is included in the Mozilla Foundation’s Public Suffix List. This list is used in recent versions of several browsers, such as Firefox, Chrome and Opera, to limit how broadly a cookie may be scoped. In other words, in browsers that support the functionality, applications in the herokuapp.com domain are prevented from setting cookies for *.herokuapp.com." https://devcenter.heroku.com/articles/cookies-and-herokuapp-com
本地 COOKIES
已部署 COOKIES
解释:虽然 API 和前端都有 .herokuapp.com,但这并不会使它们 在同一个域上。它在上面的 Heroku 文章中有解释。这意味着 *.herokuapp.com 之间的所有请求都被视为 cross-site 而不是 same-site.
解决方案
由于axios携带了laravel_sessioncookie,所以只剩下xsrf-tokencookie的问题了。要解决这个问题,必须购买一个域名,并为每个域名设置子域名。就我而言,我的 React 前端现在位于 www.jarcalculator.me while my Laravel backend is now at api.jarcalculator.me。由于它们现在是同一站点,无论它们部署在哪里(React 移至 Git 中心页面,而 Laravel 在 Heroku),可以自动设置 cookie。
通过 Github Student Pack 申请我的免费域名,终于解决了我的问题。我将我的 React 应用程序的域名设置为 www.jarcalculator.me,同时将我的 Laravel 应用程序的域名设置为 api.jarcalculator.me。由于它们现在是同一域 jarcalculator.me 的子域,包含 CSRF 令牌和 laravel_session 令牌的 cookie 的传递是 自动 。无需修改 axios 设置。只需将 axios 的 withCredentials 设置为 true 即可。