Laravel Sanctum+Fortify Vue SPA登出419/接口401问题求助
问题:Laravel Sanctum + Fortify 实现Vue SPA认证异常
登录功能正常:调用POST /sanctum/csrf-cookie可在客户端设置Cookie,携带该Cookie的X-XSRF-TOKEN头和withCredentials参数调用POST /login能完成认证。但出现两个异常:
- 调用
POST /logout时,即使携带CSRF令牌,仍返回419 unknown status csrf-token mismatch错误 - 调用
GET api/users/auth返回401 unauthorized(响应内容为unauthenticated)
已完成相关配置:cors.php路径设置、.env变量配置,以及针对SPA认证的fortify.php和fortifyServiceProvider.php配置。
登录代码
function getCookie(name) { const value = document.cookie const parts = value.split(name) if (parts.length === 2) { return parts.pop().split(';').shift() } } const login = async () => { error.value = null const payload = { email: email.value, password: password.value } axios.get('http://localhost:80/sanctum/csrf-cookie').then(() => { const csrfToken = getCookie('XSRF-TOKEN') axios .post('http://localhost:80/login', payload, { headers: { 'X-XSRF-TOKEN': decodeURIComponent(csrfToken) }, withCredentials: true }) .then((response) => { if (response.data.error) { error.value = response.data.error } else { router.push('/') } }) }) }
登出代码
const logout = async () => { const csrfToken = getCookie('XSRF-TOKEN') axios .post('http://localhost:80/logout', { headers: { 'X-XSRF-TOKEN': decodeURIComponent(csrfToken) }, withCredentials: true }) .then(router.push('/login')) }
解决方法
1. 修正登出请求的参数位置
axios.post的第二个参数是请求体数据,第三个参数才是配置项(含headers、withCredentials等)。当前登出代码把配置项放到了第二个参数的位置,导致headers未被正确识别,这是419错误的核心原因。
修正后的登出代码:
const logout = async () => { try { // 可选:登出前重新获取CSRF令牌,避免令牌过期 await axios.get('http://localhost:80/sanctum/csrf-cookie'); // 第二个参数传空对象(无请求体),第三个参数放配置 await axios.post('http://localhost:80/logout', {}, { withCredentials: true }); router.push('/login'); } catch (err) { console.error('登出失败:', err); } }
2. 简化axios配置,自动处理CSRF令牌
axios会自动从cookie中读取XSRF-TOKEN并添加到请求头,无需手动获取和设置。建议全局配置axios,减少重复代码:
// 在项目入口文件(如main.js)中配置 import axios from 'axios'; axios.defaults.baseURL = 'http://localhost:80'; axios.defaults.withCredentials = true; // 全局开启携带凭证
配置后,登录代码可简化为:
const login = async () => { error.value = null; const payload = { email: email.value, password: password.value }; try { await axios.get('/sanctum/csrf-cookie'); const response = await axios.post('/login', payload); if (response.data.error) { error.value = response.data.error; } else { router.push('/'); } } catch (err) { error.value = '登录失败,请检查账号密码'; } }
3. 检查后端关键配置
- cors.php:确保
supports_credentials设为true,paths包含所有需要跨域的路由:'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'], 'supports_credentials' => true, - .env:确认会话和Sanctum的域名配置正确(本地开发示例):
SESSION_DOMAIN=localhost SANCTUM_STATEFUL_DOMAINS=localhost:5173 # 你的Vue项目端口 - fortify.php:确保禁用视图,适配SPA:
'views' => false, 'features' => [ Features::login(), Features::logout(), // 其他需要的功能 ],
4. 验证API路由的认证中间件
确保api/users/auth路由使用了auth:sanctum中间件:
Route::get('/api/users/auth', function () { return auth()->user(); })->middleware('auth:sanctum');
内容的提问来源于stack exchange,提问作者johnny shepherd
相关产品推荐
相关产品推荐

