You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel9/Angular13 SPA Sanctum认证报No Session错误如何解决

问题描述
  • 运行环境:Angular 13 单页应用 + Laravel 9 后端 + Sanctum 认证体系
  • 基础现象:可正常获取 CSRF Cookie 并完成登录认证流程,但所有受保护 API 接口请求均返回 No Session 错误;初期排查发现 Angular 侧读取的会话 Cookie 与 Laravel 服务端生成的不匹配,尝试多组 SESSION_DOMAIN、SANCTUM_STATEFUL_DOMAINS 配置均未解决;注释掉这两个配置项后,前后端 Cookie 值可匹配,但请求受保护接口仍返回 401 响应,提示 message: "Unauthenticated."
  • 现有架构:Angular 侧对 /sanctum、/api 路径做代理转发,两类接口均通过 localhost:4200 域名访问
  • 已尝试的 .env 配置如下:
APP_URL=https://[assigned alias].ngrok.io
SESSION_DOMAIN=[assigned alias].ngrok.io
SANCTUM_STATEFUL_DOMAINS=[assigned alias].ngrok.io

APP_URL=https://[alias].tunnelto.dev
SESSION_DOMAIN=.tunnelto.dev
SANCTUM_STATEFUL_DOMAINS=[alias].tunnelto.dev

APP_URL=http://dev.local:4200
SESSION_DOMAIN=.dev.local
SANCTUM_STATEFUL_DOMAINS=dev.local:4200

APP_URL=http://localhost:4200
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:4200
  • Angular 侧请求实现代码:
const httpOptions = {
    headers: new HttpHeaders({ 
        'Access-Control-Allow-Origin':'*',
        'Access-Control-Allow-Credentials':'true',
        'Accept': 'application/json',
    }),
    withCredentials: true,
};

...

checkSession() {
    return this.http.post(apiUrl + '/session', {}, httpOptions);
}
  • 排查日志:逐步骤对比浏览器、服务端存储的会话 Cookie,二者值逐次匹配,但每次请求后 Cookie 值都会刷新:
Browser Cookie between CSRF and Auth:
eyJpdiI6Ilk3M09RSU0zdVhae...

Server Cookie from Auth:
eyJpdiI6Ilk3M09RSU0zdVhae...

Browser Cookie between Auth and Session Check:
eyJpdiI6Ill1SWtOSlNXZytGQ...

Server Cookie from Session Check:
eyJpdiI6Ill1SWtOSlNXZytGQ...

Browser Cookie after Session Check:
eyJpdiI6InRrRlNodHVORXVtS...
修复方案

按以下顺序逐一排查调整,全部配置正确后问题即可解决:

1. 删除Angular请求头中错误的CORS字段

Access-Control-Allow-Origin、Access-Control-Allow-Credentials 是服务端返回的CORS响应头,前端主动在请求中携带这两个字段会触发CORS预检异常,直接从请求头中删除,修正后代码如下:

const httpOptions = {
    headers: new HttpHeaders({ 
        'Accept': 'application/json',
    }),
    withCredentials: true,
};

2. 修正Laravel中间件加载顺序

打开 app/Http/Kernel.php,将 Sanctum 提供的 EnsureFrontendRequestsAreStateful 中间件放到 api 中间件组的最顶部,该中间件是SPA会话认证的核心,位置错误会导致会话无法被正确加载:

protected $middlewareGroups = [
    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // 必须放在最前面
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

注意:不要给API路由套web中间件组,否则会触发CSRF校验报错。

3. 固定本地开发环境配置

本地走Angular代理的场景下,直接使用以下配置即可,不需要测试多域名、前缀点等无效配置:

APP_URL=http://localhost:4200
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:4200
# 本地HTTP访问必须设为false,HTTPS环境调整为true
SESSION_SECURE_COOKIE=false
SESSION_SAME_SITE=lax
# 会话驱动默认用file即可,不要随意切换为其他驱动
SESSION_DRIVER=file

配置完成后执行 php artisan config:clear 清除配置缓存。

4. 补全Angular代理的Cookie重写规则

代理配置缺少Cookie重写规则会导致后端返回的会话Cookie无法正确写入浏览器当前域,打开Angular的 proxy.conf.json,给两个代理规则补充配置:

{
  "/sanctum": {
    "target": "http://127.0.0.1:8000", // 替换为实际的Laravel服务地址
    "secure": false,
    "changeOrigin": true,
    "cookieDomainRewrite": "localhost"
  },
  "/api": {
    "target": "http://127.0.0.1:8000",
    "secure": false,
    "changeOrigin": true,
    "cookieDomainRewrite": "localhost"
  }
}

5. 修复Laravel会话目录权限

日志中每次请求后Cookie值都会刷新,本质是Laravel无法写入会话文件,每次请求都生成新会话,自然无法保留登录状态。给项目storage目录递归赋可写权限:

chmod -R 755 storage
# Windows/WSL环境将用户组替换为当前运行PHP的用户即可
chown -R www-data:www-data storage

6. 严格遵循请求顺序

认证相关请求必须按以下顺序发起,不能跳步:

  • 第一步:请求 GET /sanctum/csrf-cookie,等待浏览器写入XSRF-TOKEN Cookie
  • 第二步:发起登录请求,Angular会自动从Cookie中读取XSRF-TOKEN携带到请求头
  • 第三步:登录成功后再请求受保护接口

内容的提问来源于stack exchange,提问作者Tim Ferrill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:51:27