跨域下React通过Axios请求Laravel API报CSRF令牌不匹配错误
Laravel Sanctum 前后端分离登录跨域报错修复
你碰到的ERR_NETWORK无状态码错误,本质是跨域携带Cookie场景下CORS配置不符合浏览器规范,和Sanctum的EnsureFrontendRequestsAreStateful中间件直接相关:当请求开启withCredentials: true要跨域带Cookie时,浏览器强制要求后端不能用通配符*匹配允许源,否则直接拦截响应,前端拿不到任何有效状态码。
第一步:修正CORS配置违规项
你当前config/cors.php里allowed_origins设为['*']是核心错误,凭证模式下通配符源直接违反CORS规范,必须明确填写前端的实际访问地址,同时补全Cookie相关的响应头暴露配置,修改后内容如下:
'paths' => ['*'], 'allowed_methods' => ['*'], // 禁止用*!明确写前端实际访问地址,本地React默认跑3000端口就填对应地址,生产环境替换为线上前端域名 'allowed_origins' => ['http://localhost:3000', 'https://你的前端线上域名'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], // 必须暴露XSRF相关响应头,否则前端无法读取写入的Cookie 'exposed_headers' => ['XSRF-TOKEN', 'laravel_session'], 'max_age' => 0, 'supports_credentials' => true,
改完配置务必执行
php artisan config:clear清除配置缓存,否则修改不会生效。
第二步:对齐Sanctum和Session配置
打开config/sanctum.php找到stateful配置项,把前端访问域名加进去,这个配置的作用是告诉Sanctum哪些来源的请求需要走Cookie+CSRF的有状态鉴权,不要把后端API域名本身加入列表:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:3000,127.0.0.1,127.0.0.1:3000,你的前端线上域名', env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '' ))),
同时检查.env文件的几个关键配置:
SESSION_DOMAIN:本地开发前后端都用localhost不同端口时,设为.localhost(前面带点,兼容同域下不同端口);生产环境前后端为同根域不同子域时设为.你的根域名.com,完全跨域本地测试可先留空SANCTUM_STATEFUL_DOMAINS:和上面sanctum配置的域名对应,本地环境填localhost:3000即可SESSION_SECURE_COOKIE:本地用http访问时设为false,生产https环境设为true
第三步:统一Axios请求配置
你当前代码只在登录post请求里加了withCredentials: true,但前面获取csrf-cookie的get请求没加这个配置,会导致XSRF-TOKEN Cookie无法正常写入浏览器。建议直接设置Axios全局默认配置,不用每个请求单独传参:
// 在Axios初始化位置添加全局配置 axios.defaults.withCredentials = true; axios.defaults.baseURL = 'http://localhost:8000'; // 后端API根地址 axios.defaults.headers.common['Accept'] = 'application/json'; axios.defaults.headers.common['Content-Type'] = 'application/json'; // Axios默认的xsrf配置本身就是正确的,无需额外修改:默认读XSRF-TOKEN Cookie,自动放到X-XSRF-TOKEN请求头 // 登录方法可简化为 async function submitForm(e) { e.preventDefault(); const body = { email, password }; // 全局已开withCredentials,请求会自动携带、写入Cookie await axios.get('/sanctum/csrf-cookie'); const res = await axios.post('/api/login', body); console.log(res); }
相关现象说明
- 禁用
EnsureFrontendRequestsAreStateful中间件后请求正常,是因为这个中间件关闭后,Sanctum不再要求SPA请求走Cookie+CSRF校验,请求退化为无状态模式,不会触发浏览器的跨域凭证校验逻辑,但会丢失Sanctum自带的SPA安全鉴权能力,生产环境不建议这么做 - 移除
withCredentials: true后返回419 CSRF不匹配,是因为跨域请求不带凭证时,浏览器不会存储、回传Cookie,后端拿不到前端的XSRF-TOKEN,自然校验失败
补充踩坑点
- Laravel 9+版本要确认
app/Http/Kernel.php的api中间件组里,EnsureFrontendRequestsAreStateful放在SubstituteBindings前面,中间件顺序错误也会触发异常 - 本地开发不要混用127.0.0.1和localhost访问前后端,二者虽然指向本地但属于不同源,会导致Cookie无法跨端口共享,统一用同一种域名访问即可
- 改完配置记得重启Laravel服务,同时清除浏览器下localhost相关的旧Cookie缓存,避免历史脏数据干扰
内容的提问来源于stack exchange,提问作者VVD971
相关产品推荐
相关产品推荐

