【问题标题】:RTK Query and Laravel Sanctum: CSRF Token Mismatch (Request has cookie)RTK 查询和 Laravel Sanctum:CSRF 令牌不匹配(请求有 cookie)
【发布时间】:2022-12-04 09:14:53
【问题描述】:

我正在使用 Sanctum 身份验证实现 Laravel API + React SPA。

使用 Sanctum,在请求实际登录路由之前,您需要向 /sanctum/csrf-cookie 发送请求“以初始化 csrf 保护”。

目前我有这个 RTK 查询 api:

import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { API_HOST } from "./config";

export const authApi = createApi({
  reducerPath: "authApi",
  baseQuery: fetchBaseQuery({
    baseUrl: `${API_HOST}`,
  }),
  endpoints: (builder) => ({
    initCsrf: builder.mutation<void, void>({
      query() {
        return {
          url: "sanctum/csrf-cookie",
          credentials: "include",
          headers: {
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json",
            Accept: "application/json",
          },
        };
      },
    }),
    loginUser: builder.mutation<{ access_token: string; status: string }, { username: string; password: string }>({
      query(data) {
        return {
          url: "login",
          method: "POST",
          body: data,
          credentials: "include",
          headers: {
            "X-Requested-With": "XMLHttpRequest",
            "Content-Type": "application/json",
            Accept: "application/json",
          },
        };
      },
      async onQueryStarted(args, { dispatch, queryFulfilled }) {
        try {
          await queryFulfilled;
        } catch (err) {
          console.error(err);
        }
      },
    }),
    logoutUser: builder.mutation<void, void>({
      query() {
        return {
          url: "logout",
          credentials: "include",
        };
      },
    }),
  }),
});

export const { useLoginUserMutation, useLogoutUserMutation, useInitCsrfMutation } = authApi;

然后在我的登录页面中,当用户单击登录按钮时,我调用:

const onSubmitHandler: SubmitHandler<LoginInput> = (values) => {
    initCsrf()
      .then(() => {
        loginUser(values);
      })
      .catch((err) => {
        console.error(err);
      });
  };

第一个请求有效并设置了 cookie,但第二个请求返回 419 CSRF 令牌不匹配异常。

检查请求,登录请求包含 XSRF-TOKEN cookie,其中包含我在第一个请求中获得的令牌,因此它应该可以正常工作。

这在使用相同结构的 Axios 之前有效(第一个请求建立 cookie,第二个请求包括 cookie)。

【问题讨论】:

    标签: reactjs laravel rtk-query laravel-sanctum


    【解决方案1】:

    您正在将 CSRF 令牌作为 cookie 发送,但 Laravel 期望它作为 X-XSRF-TOKEN 标头发送。

    更新您的 loginUser 端点以将令牌包含在标头中,而不是将其作为 cookie 发送:

    loginUser: builder.mutation<{ access_token: string; status: string }, { username: string; password: string }>({
        query(data) {
        return {
        url: "login",
        method: "POST",
        body: data,
        headers: {
        "X-Requested-With": "XMLHttpRequest",
        "Content-Type": "application/json",
        Accept: "application/json",
        "X-XSRF-TOKEN": document.cookie.match(/XSRF-TOKEN=([^;]+)/)[1], // add this line
        },
        };
        },
        async onQueryStarted(args, { dispatch, queryFulfilled }) {
        try {
        await queryFulfilled;
        } catch (err) {
        console.error(err);
        }
        },
        }),
    

    从 document.cookie 字符串中提取 XSRF-TOKEN cookie 的值,并将其包含在 loginUser 请求的标头中。

    【讨论】:

    • 这不是 CORS 问题。 API 目前允许我的来源。这可能是 RTK 查询的问题,因为它使用的是 axios。
    • 好吧,我编辑了我的答案以再次回答您编辑过的问题。我希望它现在必须工作。