使用Laravel Sanctum跨子域遇419 CSRF令牌不匹配问题求助
解决Laravel Sanctum跨子域认证的419 CSRF令牌不匹配问题
我之前也碰到过几乎一模一样的跨子域Sanctum认证坑,折腾了好几个小时才搞定,给你分享几个亲测有效的排查和解决方向:
1. 检查Cookie的SameSite与Secure配置
Laravel默认的Session Cookie SameSite属性是lax,这在跨子域场景下可能会被浏览器拦截。你需要修改config/session.php:
'same_site' => 'none', 'secure' => env('SESSION_SECURE_COOKIE', true),
同时在.env里确保SESSION_SECURE_COOKIE=true(因为SameSite=None必须配合HTTPS使用,生产环境一定要开启,本地开发如果用HTTP的话可以暂时设为false,但上线前记得改回来)。
2. 修正SANCTUM_STATEFUL_DOMAINS配置
这个配置很容易踩格式坑:
- 去掉.env里的引号,比如改成
SANCTUM_STATEFUL_DOMAINS=domain.com(有些环境下引号会导致解析错误) - 如果你的应用有www前缀(比如www.domain.com),要把它也加进去:
SANCTUM_STATEFUL_DOMAINS=domain.com,www.domain.com - 本地开发如果用了端口(比如domain.com:3000),必须带上端口号
3. 确保NextJS请求正确携带凭证和令牌
用axios或者fetch的时候,一定要开启携带凭证的配置,并且正确提取XSRF令牌:
用axios的示例:
import axios from 'axios'; // 先获取CSRF Cookie await axios.get('https://api.domain.com/sanctum/csrf-cookie', { withCredentials: true }); // 提取XSRF令牌 const getCsrfToken = () => { const cookie = document.cookie.split('; ').find(row => row.startsWith('XSRF-TOKEN=')); return cookie ? decodeURIComponent(cookie.split('=')[1]) : ''; }; // 登录请求 await axios.post('https://api.domain.com/login', { email: 'your-email', password: 'your-password' }, { withCredentials: true, headers: { 'X-XSRF-TOKEN': getCsrfToken() } });
如果用fetch的话,要设置credentials: 'include'。
4. 检查Laravel CORS配置
打开config/cors.php,确保这几个关键项正确:
'allowed_origins' => ['https://domain.com'], // 或者具体的前端域名,不要用*如果需要带凭证 'allowed_methods' => ['*'], 'allowed_headers' => ['*'], 'supports_credentials' => true, // 这个必须设为true,否则跨域Cookie会被拦截
5. 清除浏览器缓存或强制刷新CSRF令牌
有时候浏览器会缓存旧的CSRF Cookie,导致令牌不匹配。可以:
- 手动清除浏览器的Cookie和缓存
- 或者在Laravel的
/sanctum/csrf-cookie路由里添加缓存控制头,避免缓存:
Route::get('/sanctum/csrf-cookie', function () { return response()->json(['status' => 'ok']) ->withHeaders([ 'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Pragma' => 'no-cache', ]); });
6. 再次确认SESSION_DOMAIN的正确性
确保.env里的SESSION_DOMAIN=.domain.com,前面的点不能少,这样所有子域(包括api.domain.com和domain.com)才能共享这个Session Cookie。如果写成api.domain.com,主域的前端就无法访问这个Cookie了。
我当时主要是SameSite设置为none和CORS的supports_credentials没开启导致的问题,你可以逐个排查这些点,应该能解决419错误。
内容的提问来源于stack exchange,提问作者Carwyn Stephen
相关产品推荐
相关产品推荐

