不能直接用 Sanctum::issueToken() 给 SPA 发 token,因其生成的是 API 专用 token,而 SPA 应使用 session+CSRF 模式;强行存 token 会绕过 CSRF 防护且易受 XSS 攻击。

为什么不能直接用 Sanctum::issueToken() 给 SPA 发 token
因为 Sanctum::issueToken() 生成的是「token-based」令牌,专为 API 认证设计,而 SPA(比如 Vue/React 前端)通常走的是「session + CSRF」模式——它不手动传 token,而是靠 Laravel 的 session cookie 自动携带认证状态。强行发 token 给前端存 localStorage,反而绕过 Sanctum 的 session 保护机制,失去 CSRF 防御能力,也容易被 XSS 窃取。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- SPA 必须走
POST /login(带X-Requested-With: XMLHttpRequest或Accept: application/json),由 Sanctum 自动发放 session cookie - 确保前端请求带
withCredentials: true(Axios)或credentials: 'include'(fetch),否则浏览器不发送 cookie - 后端
config/sanctum.php中stateful域名必须包含你的前端地址,例如['localhost:5173', '127.0.0.1:5173'] - 如果用 Vite/HMR,开发时
localhost:5173和127.0.0.1:5173被视为不同源,漏写任一都会导致 419
移动端调用 sanctum/csrf-cookie 总是 419 或空响应
这是典型跨域 + cookie 配置断裂。Sanctum 的 CSRF 保护依赖两次交互:先 GET /sanctum/csrf-cookie 设置 XSRF-TOKEN cookie,再在后续请求头带上该值。移动端(尤其是 iOS WKWebView 或 Android WebView)对 third-party cookie 限制极严,且默认不自动读写 SameSite=Lax 的 cookie。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 必须在发起登录前,显式调用一次
GET /sanctum/csrf-cookie,并确认响应状态码为 204,且响应头含Set-Cookie: XSRF-TOKEN=xxx; Path=/; HttpOnly; SameSite=Lax - 检查
config/session.php中same_site设为null或'None',并确保secure为true(HTTPS 环境下必须) - 移动端 SDK(如 Flutter/Dio、React Native/Fetch)需主动提取
XSRF-TOKENcookie,并在登录请求头中设为X-XSRF-TOKEN: xxx - 若用自签名证书调试 HTTPS,iOS 会静默拒绝 Set-Cookie,务必用真实域名 + Let’s Encrypt
auth:sanctum 中间件在 API 路由里返回 401,但 auth:sanctum 在 web 路由里却没效果
根本原因是 Sanctum 的 auth:sanctum 中间件行为取决于请求是否被识别为「stateful」。它内部调用 Guard::check(),而该方法对 session 请求走 SessionGuard,对 token 请求走 TokenGuard;但如果你把 auth:sanctum 放在 api 路由组里,默认是无 session 的 token 模式,而你又没在请求头传 Authorization: Bearer xxx,自然 401。反过来,放在 web 路由组里,它期望 session cookie,但若前端没正确带 cookie,check() 就静默失败,不报错也不重定向——看起来“没效果”。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 明确区分:SPA 用
web路由 + session 认证;纯 API(如微信小程序、第三方调用)用api路由 + token 认证 - 不要混用:别在
api路由里依赖 cookie,也别在web路由里依赖Bearertoken - 验证当前 guard 类型:在中间件里临时加
dd(app('auth')->guard('sanctum')->__toString()),看是SessionGuard还是TokenGuard - API 场景下,确保用户已通过
Sanctum::createToken()创建了可持久化的 token,并由客户端安全存储
生产环境部署后,Sanctum 的 session 总是失效或跨请求丢失
绝大多数是反向代理(Nginx / Cloudflare)或负载均衡器剥离了关键 header,或未透传 cookie 属性。Sanctum 依赖的 XSRF-TOKEN 和 laravel_session cookie 对 Secure、SameSite、Domain 极其敏感,任意一项不匹配,浏览器就拒绝发送。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- Nginx 配置中必须包含:
proxy_cookie_path / "/; Secure; HttpOnly; SameSite=None"(HTTPS 下)或SameSite=Lax(非 HTTPS 开发环境) - 确保
APP_URL和SESSION_DOMAIN环境变量与实际访问域名完全一致(包括 www/非 www、端口) - Cloudflare 开启「Always Use HTTPS」的同时,需在 Page Rule 中设置「Disable Security」或确保「SSL/TLS → Edge Certificates」启用,并勾选「Authenticated Origin Pulls」
- 多服务器部署时,
APP_KEY必须相同,否则 session 解密失败,表现就是每次请求都新建 session
最常被忽略的一点:前端发请求时,credentials 配置和后端 SESSION_SAME_SITE 必须逻辑自洽——不是设成 None 就万事大吉,它强制要求 Secure,而本地开发 HTTP 环境下只能用 Lax 或 Strict。这点一旦配错,整个认证链就断在第一步。



















