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_sessionXSRF_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 即可。