如何在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绑定到同一个根域名的子域名下:
修改系统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。- Windows:打开
调整服务启动地址:
- 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启动时指定host:
二、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('更新失败'); } }
四、验证效果
- 启动Laravel和Next.js服务,访问
http://web.myapp.test:3000 - 提交登录表单,成功后打开浏览器开发者工具(Application/Storage标签),你会看到
auth_tokenCookie被存在.myapp.test域名下,同时api.myapp.test和web.myapp.test都能访问它 - 不管是服务端还是客户端的请求,在Network标签里查看请求头,会自动带上
Cookie: auth_token=xxx,不需要手动添加Bearer Token
五、生产环境注意事项
- HTTPS必须开启:生产环境Cookie的
secure属性要设为true,只有HTTPS协议下才能使用HttpOnly Cookie - 域名配置:把
.myapp.test换成你的实际根域名,比如.yourdomain.com,Laravel部署在api.yourdomain.com,Next.js部署在yourdomain.com或web.yourdomain.com - CORS配置更新:把
allowed_origins设为你的前端生产域名,比如['https://yourdomain.com'] - Next.js的
credentials: 'include'不能丢:生产环境依然需要在所有跨域请求里加上这个配置
为什么之前的尝试没成功?
- 直接用不同端口的localhost:跨域Origin不匹配,浏览器拒绝共享Cookie
- 手动在Next.js设置Cookie:完全没必要,Laravel可以直接设置跨域共享的Cookie,而且手动设置会多此一举,还可能导致Cookie不一致
这样配置后,你就能实现:Laravel登录后设置一次HttpOnly Cookie,Next.js的服务端和客户端请求自动携带这个Cookie,同时保持Cookie的HttpOnly安全性,不会被JS访问到~




