Laravel怎么设置跨域Cookie_Laravel中间件设置SameSite属性【避坑】

5次阅读

根本原因是浏览器SameSite策略升级:chrome 80+默认将未声明SameSite的cookie视为Lax,跨域请求下Lax阻止发送;SameSite=None必须配合Secure=true(httpS),且XSRF-Tokensession cookie均需显式设置。

Laravel怎么设置跨域Cookie_Laravel中间件设置SameSite属性【避坑】

为什么 laravel 的跨域 Cookie 总是丢失

根本原因不是 Laravel 配置错了,而是浏览器SameSite 属性的强制策略升级 —— Chrome 80+ 默认把未声明 SameSite 的 Cookie 当作 SameSite=Lax,而跨域请求(比如前端http://localhost:3000 调用 https://api.example.com)下,Lax 会直接阻止 Cookie 发送。即使你开了 withCredentials: true后端也设置了 access-Control-Allow-Credentials: true,Cookie 还是不带。

Laravel 中间件里怎么正确设置 SameSite=None

不能只改 config/session.php 里的 'same_site' => 'none' —— 这只影响 session cookie,且 Laravel 7+ 才支持该配置项;更重要的是:Chrome 要求 SameSite=None 必须配合 Secure=true(即只在 HTTPS 下发送),否则直接忽略该设置,降级为 Lax

  • config/session.php 中必须同时设:
    "secure" => env('SESSION_SECURE_COOKIE', true),
    "same_site" => 'none'
  • 开发环境(HTTP)无法真正使用 SameSite=None,浏览器会拒绝;本地调试建议用 ngroklocalhost(Chrome 对 localhost 有例外,允许 SameSite=None + Secure=false,但仅限开发)
  • 若需动态判断环境,可在中间件中手动覆盖响应头:
    return $next($request)->withCookie(cookie('XSRF-TOKEN')
    ->sameSite('None')
    ->secure(true));

跨域场景下 XSRF-TOKEN 和 session cookie 都要处理

很多人只改了 session cookie,却忽略了 Laravel 默认通过 XSRF-TOKEN Cookie + X-XSRF-TOKEN 请求头做 csrf 防护。这个 Token 也是 Cookie,同样受 SameSite 限制。

  • XSRF-TOKEN 默认由 StartSession 中间件写入,但它的 SameSite继承 session.php 配置,需显式干预
  • 推荐在 app/Http/Middleware/TrustProxies.php 后加一个中间件(如 SetSameSiteForCsrf),在响应前重写该 Cookie:
    if ($response->headers->hasCookie('XSRF-TOKEN')) {
    $cookie = $response->headers->getCookie('XSRF-TOKEN');
    $response->headers->setCookie($cookie->withSameSite('None')->withSecure(true));
    }
  • 确保前端 axios 实例已启用凭证:axios.defaults.withCredentials = true

常见错误现象和验证方式

别只看 Network 面板里 Cookie 是否“出现”,要看它是否被浏览器实际发送出去 —— 关键看请求头里有没有 Cookie: 字段,以及响应头是否有 Set-Cookie 且含 SameSite=None; Secure

  • 错误现象:UnauthenticatedCSRF token mismatch、登录后立刻 401 —— 很可能是 Cookie 没发过去
  • 检查响应头:Set-Cookie: laravel_session=xxx; expires=...; Max-Age=...; path=/; domain=.example.com; secure; HttpOnly; SameSite=None(缺 Secure 或拼写错 SameSite 都会失败)
  • Chrome 控制台 Application → Cookies 标签页里,如果某 Cookie 显示 “SameSite=None is not allowed without ‘Secure’” 就说明 Secure 缺失或环境非 HTTPS

SameSite 是浏览器层面的硬性约束,Laravel 只负责生成响应头;配错一个字母、漏掉一个 Secure、或者开发时用 HTTP 却硬设 SameSite=None,都会让整个跨域认证链断裂。

text=ZqhQzanResources