Laravel+Nuxt登录失败仍可访问仪表盘问题求助
问题排查与解决方案
核心问题定位
你的auth和guest中间件逻辑完全错误——XSRF-TOKEN不是认证令牌,它仅用于防止跨站请求伪造,和用户是否登录没有任何关联。只要访问过Laravel Sanctum接口,浏览器就会自动获取该令牌,哪怕用户未登录,所以错误凭证登录失败后,这个令牌依然存在,导致中间件误判用户已登录,放行进入仪表盘页面。
具体错误点分析
中间件判断逻辑错误
你在auth和guest中间件的客户端逻辑中,用XSRF-TOKEN作为登录状态判断依据,但这个令牌是Laravel Sanctum默认给所有访客设置的,和用户认证状态无关。真正的认证凭证是Laravel的laravel_session会话Cookie,或是你自行存储的API/JWT令牌。认证状态未同步校验
中间件仅依赖Cookie值判断状态,没有验证用户在后端的实际登录状态,导致未授权用户能绕过校验进入受保护页面。登录/登出逻辑冗余且不严谨
登录时通过额外的$fetch存储令牌,未在axios实例中自动携带认证信息;登出时重复调用两次logout接口,逻辑冗余且未确保前端状态完全清空。
修复步骤
1. 修正中间件逻辑
auth中间件(确保用户真实登录)
export default defineNuxtRouteMiddleware(async (to, from) => { const { user, me } = useAuth() // 同步后端用户状态 await me() // 用户未登录则跳转首页 if (!user.value) { return navigateTo('/') } })
guest中间件(确保用户未登录)
export default defineNuxtRouteMiddleware(async (to, from) => { const { user, me } = useAuth() await me() // 用户已登录则跳转仪表盘 if (user.value) { return navigateTo('/dashboard') } })
2. 完善axios实例的认证令牌携带
修改useAxios.js,确保请求自动带上认证凭证:
import axios from "axios"; export default function useAxios(){ const rtConfig = useRuntimeConfig() const tokenCookie = useCookie('token') let api = axios.create({ baseURL: rtConfig.public.API_URL, headers: { "Content-Type": "application/json", "Accept": "application/json", }, withCredentials: true, withXSRFToken: true }) // 请求拦截器:自动携带认证令牌 api.interceptors.request.use(config => { // 若使用JWT令牌,从Cookie中取出并设置请求头 if (tokenCookie.value) { config.headers.Authorization = `Bearer ${tokenCookie.value}` } return config }) async function csrf(){ return await api.get("/sanctum/csrf-cookie") } return { api, csrf } }
3. 优化登录/登出逻辑
修改useAuth.js,简化流程并确保状态同步:
export default function useAuth() { const user = useState('auth-user', () => null) const tokenCookie = useCookie('token') const { errorBag, transformValidationErrors, resetErrorBag } = useCustomError() const { api, csrf } = useAxios() async function me() { try { const data = await api.get("/api/me") user.value = data.data } catch (e) { user.value = null tokenCookie.value = null console.log("未授权或会话过期") } } async function login(userForm) { resetErrorBag() try { await csrf() const { data } = await api.post("/login", userForm) user.value = data.user tokenCookie.value = data.token navigateTo("/dashboard") } catch (err) { transformValidationErrors(err.response) user.value = null tokenCookie.value = null } } async function logout() { try { await api.post("/api/logout") } catch (e) { console.log("登出失败,可能会话已过期") } finally { user.value = null tokenCookie.value = null navigateTo("/") } } async function register(userForm) { resetErrorBag() try { await csrf() await api.post("/register", userForm) // 跳转邮箱验证页面 } catch (err) { transformValidationErrors(err.response) } } return { login, logout, register, errorBag, user, me } }
4. 确保Laravel后端配置正确
- 确认
config/sanctum.php的stateful数组包含你的Nuxt前端域名 - 确认
api/me路由使用auth:sanctum中间件 - 确认登录接口成功后返回用户信息及令牌(若使用JWT),或通过会话维持登录状态
关键注意事项
- 永远不要用XSRF-TOKEN判断用户登录状态,它仅用于CSRF防护,和认证无关
- 中间件必须通过后端接口验证用户实际登录状态,避免前端状态与后端不一致
- 前端状态(如user、tokenCookie)需在登录失败、登出时彻底清空
内容的提问来源于stack exchange,提问作者JayVch
相关产品推荐
相关产品推荐

