Nuxt3+Laravel12 Sanctum SPA认证:每次请求生成新会话问题
问题分析与解决方案
核心问题
你的场景下会话ID每次请求都重置,本质是浏览器未在跨端口请求中正确携带会话Cookie,导致Laravel无法识别已有会话,每次创建新会话,最终引发CSRF令牌不匹配。
疑问解答
1. localhost端口与Cookie的特性
浏览器把同一域名下的不同端口视为不同源,但Cookie的domain设为.localhost时,所有localhost:*端口都能共享该Cookie。不过部分浏览器(如Chrome)对localhost的Cookie有特殊处理,需确保Cookie的path为/,且same_site设置不阻止跨端口请求。
2. 会话ID每次变化的原因
大概率是以下某一点导致浏览器未携带会话Cookie:
- CORS配置冲突,浏览器拒绝存储/发送Cookie
- 路由中间件顺序错误,禁用了会话功能
- Axios未全局开启
withCredentials - 会话Cookie的
http_only/same_site属性限制了跨端口传输
3. 跨端口能否实现Laravel会话认证
完全可以。只要配置正确,确保Cookie能跨端口共享、请求携带credentials,Laravel就能通过database驱动维持跨请求的会话状态。
具体修复步骤
1. 清理重复CORS配置
你同时配置了官方config/cors和自定义CorsMiddleware,会导致响应头重复,浏览器可能拒绝处理。直接删除自定义的CorsMiddleware,保留官方配置:
// config/cors.php return [ 'paths' => ['api/*', 'sanctum/csrf-cookie', 'oauth/*'], 'supports_credentials' => true, 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000'], 'allowed_headers' => ['*'], 'exposed_headers' => ['XSRF-TOKEN', 'Authorization'], 'max_age' => 0, ];
2. 修正会话Cookie配置
确保config/session.php的关键属性正确:
return [ 'driver' => env('SESSION_DRIVER', 'database'), 'cookie' => env('SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session'), 'path' => '/', 'domain' => '.localhost', // 带前置点,允许所有localhost端口共享 'secure' => false, // 本地HTTP环境设为false 'http_only' => true, // 安全设置,不影响XSRF-TOKEN的获取 'same_site' => 'lax', // 跨端口请求用lax足够 ];
3. 修正路由中间件顺序
api中间件会默认禁用会话,不能把状态化路由嵌套在api中间件组里。修改routes/api.php:
Route::prefix('v1')->group(function () { // 公开路由(无需会话) Route::post('/register', [AuthController::class, 'CustomerRegister']); // 状态化路由(登录+受保护接口) Route::middleware([EnsureFrontendRequestsAreStateful::class])->group(function () { Route::post('/login', [AuthController::class, 'AdminAffiliateLogin']); Route::post('/logincustomer', [AuthController::class, 'CustomerLogin']); Route::middleware('auth:sanctum')->group(function () { Route::post('/logout', [AuthController::class, 'logout']); Route::get('/getallbrochure', [BrochureController::class, 'index']); Route::get('/getbrochure/{id}', [BrochureController::class, 'show']); Route::post('/uploadbrochure', [BrochureController::class, 'store']); Route::get('/deletebrochure/{id}', [BrochureController::class, 'destroy']); Route::put('/updatebrochure/{id}', [BrochureController::class, 'update']); }); }); });
4. 统一Axios配置,确保全局携带Credentials
在Nuxt 3的plugins/axios.ts中全局配置,避免多实例遗漏:
import axios from 'axios' export default defineNuxtPlugin(() => { const apiBaseUrl = 'http://localhost:8000/api/v1' const axiosInstance = axios.create({ baseURL: apiBaseUrl, withCredentials: true, }) // 请求前自动获取CSRF令牌(针对修改类请求) axiosInstance.interceptors.request.use(async (config) => { if (['post', 'put', 'delete'].includes(config.method?.toLowerCase() || '')) { await axios.get('http://localhost:8000/sanctum/csrf-cookie', { withCredentials: true }) const xsrfToken = useCookie('XSRF-TOKEN').value if (xsrfToken) config.headers['X-XSRF-TOKEN'] = xsrfToken } return config }) return { provide: { axios: axiosInstance } } })
5. 验证会话Cookie状态
打开浏览器F12开发者工具:
- 到Application标签,确认
laravel_session(或自定义会话Cookie名)存在,domain为.localhost、path为/ - 到Network标签,查看后续请求的请求头是否包含
Cookie: laravel_session=xxx; XSRF-TOKEN=xxx
6. 确保会话表正常
如果之前未生成会话表,执行:
php artisan session:table php artisan migrate
内容的提问来源于stack exchange,提问作者Accio
相关产品推荐
相关产品推荐

