You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Laravel API(localhost:8000)与Next.js(localhost:3000)之间共享HttpOnly认证Cookie?

如何在Laravel API(localhost:8000)与Next.js(localhost:3000)之间共享HttpOnly认证Cookie?

这问题核心是跨域Origin的Cookie共享限制——localhost:8000和3000属于不同的源,浏览器默认不会在它们之间共享Cookie。同时HttpOnly的特性又要求我们不能用JS操作Cookie,所以得从跨域配置、Cookie域名设置和请求凭证这几个角度来解决,我给你一步步捋:

一、先解决本地开发的跨域Origin问题:用统一根域名的子域名

浏览器判断两个地址是否同源,会看协议、域名、端口三者是否完全一致,所以不同端口的localhost是两个独立的源,Cookie自然无法共享。本地开发我们可以通过修改hosts文件,把Laravel和Next.js绑定到同一个根域名的子域名下:

  1. 修改系统hosts文件:

    • Windows:打开C:\Windows\System32\drivers\etc\hosts(需要管理员权限)
    • Mac/Linux:打开/etc/hosts
    • 添加两行配置:
      127.0.0.1 api.myapp.test
      127.0.0.1 web.myapp.test
      

    这样api.myapp.test指向Laravel,web.myapp.test指向Next.js,两者共享同一个根域名.myapp.test

  2. 调整服务启动地址:

    • Laravel启动时指定host:
      php artisan serve --host=api.myapp.test --port=8000
      
    • Next.js启动时可以在package.json的dev脚本里加--host web.myapp.test,或者直接访问http://web.myapp.test:3000(hosts已经映射了,Next.js默认监听所有地址)

二、Laravel端关键配置:CORS + Cookie域名设置

要让Laravel设置的Cookie能被Next.js共享,需要调整CORS规则和Cookie的domain参数:

1. 配置CORS允许携带凭证

打开config/cors.php,修改以下配置:

return [
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['http://web.myapp.test:3000'], // 允许Next.js的源
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true, // 必须设为true,允许跨域请求携带Cookie
];

2. 调整登录接口的Cookie设置

在你返回登录响应的代码里,把Cookie的domain参数设为根域名.myapp.test,这样所有子域名都能共享这个Cookie:

$cookie = cookie(
    'auth_token', 
    $token, 
    60, // 过期时间(分钟)
    '/', // 路径
    '.myapp.test', // 根域名,关键!让子域名共享Cookie
    env('APP_ENV') === 'production', // secure:生产环境开HTTPS才设为true
    true, // httpOnly:保持true,防止XSS
    false,
    'lax' // sameSite:lax适合大部分场景
);

return response()
    ->json([
        'status' => 'success',
        'user' => $user->only('id', 'name', 'email', 'phone'),
    ])
    ->cookie($cookie);

注意:这里不需要返回token字段给前端了,因为我们靠Cookie做认证,前端不需要拿到Token字符串。

三、Next.js端配置:请求时携带凭证

Next.js的所有请求(不管是服务端还是客户端)都要加上credentials: 'include',这样浏览器会自动把共享的HttpOnly Cookie附加到请求里:

1. 客户端组件的请求(Client Components)

比如登录请求或者其他客户端接口请求:

// 登录示例(Client Component里的函数)
async function handleLogin(formData) {
  const res = await fetch('http://api.myapp.test:8000/api/login', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email: formData.get('email'),
      password: formData.get('password'),
    }),
    credentials: 'include', // 关键:告诉浏览器携带/保存Cookie
  });

  if (res.ok) {
    // 登录成功,不需要处理Token,Cookie已经由Laravel设置好
    // 可以跳转到首页或者其他页面
  }
}

// 后续客户端请求示例(比如拉取用户信息)
async function fetchUser() {
  const res = await fetch('http://api.myapp.test:8000/api/user', {
    credentials: 'include', // 自动带上Cookie
  });
  const data = await res.json();
  return data;
}

2. 服务端组件/服务端动作的请求(Server Components/Server Actions)

服务端的请求同样需要加上credentials: 'include',因为Next.js服务端会模拟浏览器的Cookie上下文:

// Server Component示例
async function UserProfile() {
  const res = await fetch('http://api.myapp.test:8000/api/user', {
    credentials: 'include', // 自动带上用户的Cookie
    cache: 'no-store', // 避免缓存,保证每次请求都是最新的用户信息
  });
  const user = await res.json();

  return <div>欢迎{user.name}</div>;
}

// Server Action示例
async function updateUserProfile(formData) {
  const res = await fetch('http://api.myapp.test:8000/api/profile', {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: formData.get('name'),
      phone: formData.get('phone'),
    }),
    credentials: 'include', // 带上认证Cookie
  });

  if (!res.ok) {
    throw new Error('更新失败');
  }
}

四、验证效果

  1. 启动Laravel和Next.js服务,访问http://web.myapp.test:3000
  2. 提交登录表单,成功后打开浏览器开发者工具(Application/Storage标签),你会看到auth_token Cookie被存在.myapp.test域名下,同时api.myapp.testweb.myapp.test都能访问它
  3. 不管是服务端还是客户端的请求,在Network标签里查看请求头,会自动带上Cookie: auth_token=xxx,不需要手动添加Bearer Token

五、生产环境注意事项

  1. HTTPS必须开启:生产环境Cookie的secure属性要设为true,只有HTTPS协议下才能使用HttpOnly Cookie
  2. 域名配置:把.myapp.test换成你的实际根域名,比如.yourdomain.com,Laravel部署在api.yourdomain.com,Next.js部署在yourdomain.comweb.yourdomain.com
  3. CORS配置更新:把allowed_origins设为你的前端生产域名,比如['https://yourdomain.com']
  4. Next.js的credentials: 'include'不能丢:生产环境依然需要在所有跨域请求里加上这个配置

为什么之前的尝试没成功?

  1. 直接用不同端口的localhost:跨域Origin不匹配,浏览器拒绝共享Cookie
  2. 手动在Next.js设置Cookie:完全没必要,Laravel可以直接设置跨域共享的Cookie,而且手动设置会多此一举,还可能导致Cookie不一致

这样配置后,你就能实现:Laravel登录后设置一次HttpOnly Cookie,Next.js的服务端和客户端请求自动携带这个Cookie,同时保持Cookie的HttpOnly安全性,不会被JS访问到~

火山引擎 最新活动