React 18 SPA对接Laravel 10 API遇CSRF token mismatch错误求助
React 18 SPA 对接 Laravel 10 Sanctum+Breeze API 认证问题解决
问题场景
开发基于React 18的SPA,对接集成Sanctum认证、安装Breeze API脚手架的Laravel 10 API。遵循官方文档操作后问题仍未解决,尝试了大量开发者方案及Sanctum前身Airlock时期的旧帖。在WAMP中配置localdomain主域名与api.localdomain子域名测试,GET请求正常,POST请求始终报错。排查发现Axios发送POST数据时未携带Cookie,且Laravel未设置X-XSRF-TOKEN Cookie,导致返回419状态码(CSRF token mismatch)。
现有配置信息
Axios 配置(axios.js)
import axios from "axios"; export default axios.create({ baseURL: 'http://api.localdomain', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, withCredentials: true })
.env 配置
APP_NAME=localdomain APP_ENV=local APP_KEY=base64:SjhdnO/kZ2IMWGKEdgrw+a5e1eToxvtLHsbJvwf0dAs= APP_DEBUG=true APP_URL=http://api.localdomain FRONTEND_URL=http://localdomain SESSION_DRIVER=cookie SESSION_LIFETIME=120 MEMCACHED_HOST=127.0.0.1 SESSION_DOMAIN=.localdomain SANCTUM_STATEFUL_DOMAINS=api.localdomain
config/cors.php 配置
'paths' => [ 'api/*', 'login', 'logout', 'register', 'user/password', 'forgot-password', 'reset-password', 'sanctum/csrf-cookie', 'user/profile-information', 'email/verification-notification', ], 'allowed_methods' => ['*'], 'allowed_origins' => [env('FRONTEND_URL')], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true,
config/session.php 配置
'domain' => env('SESSION_DOMAIN'), 'http_only' => true, 'same_site' => 'lax',
config/sanctum.php 配置
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf('%s%s%s', 'api.localdomain,localdomain,127.0.0.1,127.0.0.1:8000,::1', env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '', env('FRONTEND_URL') ? ','.parse_url(env('FRONTEND_URL'), PHP_URL_HOST) : '' ))), 'middleware' => [ 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, ],
认证路由(routes/auth.php)
<?php use App\Http\Controllers\Auth\AuthenticatedSessionController; use App\Http\Controllers\Auth\NewPasswordController; use App\Http\Controllers\Auth\PasswordResetLinkController; use App\Http\Controllers\Auth\RegisteredUserController; use Illuminate\Support\Facades\Route; Route::post('/register', [RegisteredUserController::class, 'store'])->middleware('guest'); Route::post('/login', [AuthenticatedSessionController::class, 'store'])->middleware('guest'); Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])->middleware('auth'); Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])->middleware('guest'); Route::post('/reset-password', [NewPasswordController::class, 'store'])->middleware('guest');
Breeze 安装命令
# Install Breeze and dependencies... composer require laravel/breeze --dev php artisan breeze:install api
解决步骤
1. 修正 Sanctum 状态域配置
.env 中 SANCTUM_STATEFUL_DOMAINS 需要包含前端主域名,修改为:
SANCTUM_STATEFUL_DOMAINS=localdomain,api.localdomain
执行以下命令清除配置缓存:
php artisan config:clear
2. 强制预请求获取 CSRF Cookie
在发送任何POST请求(如登录)前,必须先发送GET请求到 /sanctum/csrf-cookie,触发Laravel设置XSRF-TOKEN Cookie。React中示例代码:
import axios from './axios'; async function handleLogin(email, password) { // 先获取CSRF cookie await axios.get('/sanctum/csrf-cookie'); // 再发送登录请求 const response = await axios.post('/login', { email, password }); return response; }
3. 调整 Session Cookie 配置
修改 config/session.php,确保前端可访问Cookie:
'domain' => '.localdomain', 'secure' => false, // 本地环境禁用,生产环境根据HTTPS配置 'http_only' => false, // 允许JS读取Cookie 'same_site' => 'lax',
执行配置缓存清除命令生效。
4. 更新 CORS 暴露头配置
修改 config/cors.php,添加XSRF-TOKEN到暴露头:
'exposed_headers' => ['XSRF-TOKEN'],
5. 验证 Cookie 与请求头
- 打开浏览器开发者工具Application标签,检查
localdomain下是否存在laravel_session和XSRF-TOKENCookie,Domain为.localdomain - 发送POST请求时,查看Network标签的请求头,确认包含
Cookie字段和X-XSRF-TOKEN头
6. 全量清除缓存
执行以下命令确保所有配置生效:
php artisan config:clear php artisan cache:clear php artisan route:clear
内容的提问来源于stack exchange,提问作者jgarcias
相关产品推荐
相关产品推荐

