Angular请求Laravel CSRF接口时每次生成新令牌,与浏览器请求行为不一致的原因
根本原因分析
Laravel CSRF 令牌的绑定规则
Laravel 的 csrf_token() 返回值完全绑定当前会话(Session):
- 令牌会存储在服务端 Session 上下文中
- 会话身份完全靠客户端携带的
SESSIONCookie(Laravel 默认会话 Cookie 名)识别 - 只有客户端携带的 Cookie 和服务端 Session 匹配时,才会返回同一个固定令牌;如果没有有效会话 Cookie,Laravel 会生成全新 Session,返回全新的 CSRF 令牌。
不同场景的行为差异来源
直接浏览器访问、Postman 请求返回固定令牌的原因
- 直接访问
http://token.loc/token属于同域请求,浏览器会自动携带该域名下的所有 Cookie,Laravel 能识别到同一个 Session,因此令牌固定。 - Postman/Insomnia 这类 API 工具会自动保存接口返回的所有 Cookie,后续请求自动携带,也能维持同一个 Session,因此令牌固定。
Angular 跨域请求每次返回新令牌的原因
你的前端运行在 http://localhost:4200,请求的接口在 http://token.loc,属于跨域请求,存在两个默认限制:
- Angular HttpClient 默认不对跨域请求携带 Cookie:你当前的请求没有开启
withCredentials配置,浏览器会自动丢弃跨域请求中需要传递的SESSIONCookie,Laravel 每次都将请求识别为新访客,生成全新 Session 和令牌。 - 就算开启了前端的凭证携带配置,如果 Laravel 端 CORS 规则没有允许跨域凭证,浏览器也会拦截 Cookie 的传递。
修复方案
1. 调整 Angular 端请求配置
修改 token.service.ts 的 get 方法,开启跨域请求携带 Cookie:
get(): Observable<any> { return this.http.get(this.url, { withCredentials: true // 跨域请求自动携带 Cookie(含 Session Cookie) }); }
如果所有接口都需要携带凭证,也可以封装全局 HTTP 拦截器统一配置该参数,不用每个请求单独设置。
2. 调整 Laravel 端 CORS 配置
修改 Laravel 项目的 config/cors.php(如果没有该文件,可执行 php artisan vendor:publish --tag=cors 生成):
- 将
supports_credentials设为true,允许跨域请求携带凭证 allowed_origins不能使用通配符*,需要明确指定前端地址http://localhost:4200
参考配置示例:
'paths' => ['token', 'api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:4200'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'supports_credentials' => true, 'max_age' => 0,
3. 适配跨站 Cookie的 SameSite 限制
现代浏览器默认对跨站 Cookie 启用 SameSite=Lax 限制,如果 localhost 和 token.loc 被浏览器判定为跨站,还需要调整 Laravel 的 Session 配置(修改 config/session.php):
- 将
same_site设为'none' - 本地 HTTP 开发环境将
secure设为false(生产环境必须设为true配合 HTTPS 部署)
'same_site' => 'none', 'secure' => env('SESSION_SECURE_COOKIE', false),
提示:Chrome 浏览器要求
SameSite=None的 Cookie 必须同时配置Secure属性,本地 HTTP 环境如果适配麻烦,可以直接用 Nginx 反向代理,把前端的localhost:4200/api/*路径转发到token.loc服务,完全规避跨域问题。
内容的提问来源于stack exchange,提问作者Daniel Częstki
相关产品推荐
相关产品推荐

