You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel+Nuxt登录失败仍可访问仪表盘问题求助

问题排查与解决方案

核心问题定位

你的auth和guest中间件逻辑完全错误——XSRF-TOKEN不是认证令牌,它仅用于防止跨站请求伪造,和用户是否登录没有任何关联。只要访问过Laravel Sanctum接口,浏览器就会自动获取该令牌,哪怕用户未登录,所以错误凭证登录失败后,这个令牌依然存在,导致中间件误判用户已登录,放行进入仪表盘页面。

具体错误点分析

  1. 中间件判断逻辑错误
    你在auth和guest中间件的客户端逻辑中,用XSRF-TOKEN作为登录状态判断依据,但这个令牌是Laravel Sanctum默认给所有访客设置的,和用户认证状态无关。真正的认证凭证是Laravel的laravel_session会话Cookie,或是你自行存储的API/JWT令牌。

  2. 认证状态未同步校验
    中间件仅依赖Cookie值判断状态,没有验证用户在后端的实际登录状态,导致未授权用户能绕过校验进入受保护页面。

  3. 登录/登出逻辑冗余且不严谨
    登录时通过额外的$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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:06:15