云计算百科
云计算领域专业知识百科平台

路由与布局扫盲篇:登录态与路由守卫 | token 校验、白名单、重定向

同学们好,我是 Eugene(尤金),一个拥有多年中后台开发经验的前端工程师~

(Eugene 发音很简单,/juːˈdʒiːn/,大家怎么顺口怎么叫就好)

你是否也有过:明明学过很多技术,一到关键时候却讲不出来、甚至写不出来?

你是否也曾怀疑自己,是不是太笨了,明明感觉会,却总差一口气?

就算想沉下心从头梳理,可工作那么忙,回家还要陪伴家人。

一天只有24小时,时间永远不够用,常常感到力不从心。

技术行业,本就是逆水行舟,不进则退。

如果你也有同样的困扰,别慌。

从现在开始,跟着我一起心态归零,利用碎片时间,来一次彻彻底底的基础扫盲。

这一次,我们一起慢慢来,扎扎实实变强。

不搞花里胡哨的理论堆砌,只分享看得懂、用得上的前端干货,

咱们一起稳步积累,真正摆脱“面向搜索引擎写代码”的尴尬。


一、先搞清楚几个概念

1.1 什么是登录态?

登录态就是「当前用户是否已经登录」的状态。前端通常用 token 来表示:

  • 有 token:已登录
  • 没有 token:未登录

token 一般存在 localStorage 或 sessionStorage 里,登录成功后由后端返回,后面每次请求都带上,后端根据 token 识别用户。

1.2 什么是路由守卫?

路由守卫就是路由跳转前的「关卡」,用来统一处理跳转逻辑。Vue Router 里最常用的就是 router.beforeEach:

  • 每次路由跳转前都会执行
  • 可以在这里做 token 校验、权限判断
  • 可以通过 next() 控制是放行还是拦截、重定向

二、整体流程:beforeEach 里要解决什么问题?

核心就三步:

用户访问某个页面

beforeEach 拦截

判断:有没有 token?
├─ 有 token → 已登录,放行
└─ 没 token → 未登录

目标路由在白名单吗?
├─ 在(登录页、404 等)→ 放行
└─ 不在 → 拦截,重定向到登录页


三、白名单:哪些路由不需要登录?

白名单就是「不用登录也能访问」的路由列表,比如:

  • 登录页 /login
  • 注册页 /register
  • 404 页 /404
  • 首页 /(有些产品首页可以匿名访问)

做法:把白名单路径写在一个数组里,用 includes 判断当前路径是否在白名单中。


四、重定向逻辑:去哪、回哪

常见两种需求:

  • 未登录访问需要登录的页面 → 跳到登录页
  • 登录后想回到「之前想访问的页面」

第二个用 redirect 参数实现:在跳转登录页时把目标地址带上,登录成功后根据 redirect 跳回去。


五、beforeEach 里「应该」做什么?

  • 做登录态检查:根据 token 判断是否登录
  • 白名单判断:判断当前路由是否在白名单
  • 简单重定向:未登录时重定向到登录页,并带上 redirect
  • 放行:满足条件时调用 next() 放行
  • 可以简单概括为:只做和「能不能进这个页面」相关的判断,别的都尽量放外面。


    六、beforeEach 里「不应该」做什么?

  • 异步请求:不在 beforeEach 里发接口请求(如获取用户信息)。因为 beforeEach 会被频繁调用,容易造成重复请求、闪烁和性能问题。
  • 复杂业务逻辑:比如获取菜单、权限树等,应放到登录后或主布局加载时。
  • 全局副作用:比如修改 Vuex/Pinia 里很多状态,容易让逻辑难以追踪。
  • 过度依赖 router:避免在守卫里做大量路由遍历、动态添加等复杂操作,保持守卫简洁。

  • 七、完整代码示例

    下面是一个完整的示例,包含:

    • 白名单配置
    • token 获取
    • redirect 保存与使用
    • 清晰的结构和注释

    // router/index.js
    import { createRouter, createWebHistory } from 'vue-router'
    import { getToken } from '@/utils/auth' // 假设你有这个工具函数

    const routes = [
    {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue'),
    meta: { title: '登录', requireAuth: false }
    },
    {
    path: '/home',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
    meta: { title: '首页', requireAuth: true }
    },
    {
    path: '/user',
    name: 'User',
    component: () => import('@/views/User.vue'),
    meta: { title: '个人中心', requireAuth: true }
    },
    {
    path: '/:pathMatch(.*)*',
    name: 'NotFound',
    component: () => import('@/views/404.vue'),
    meta: { title: '404', requireAuth: false }
    }
    ]

    const router = createRouter({
    history: createWebHistory(),
    routes
    })

    // ========== 白名单:不需要登录就能访问的路由 ==========
    const WHITELIST = ['/login', '/register', '/404']

    /**
    * 判断目标路由是否在白名单内
    * @param {string} path – 路由路径
    * @returns {boolean}
    */

    function isInWhitelist(path) {
    return WHITELIST.some(item => path.startsWith(item))
    }

    router.beforeEach((to, from, next) => {
    // 1. 设置页面标题(可选,和登录校验无直接关系)
    document.title = to.meta?.title || '我的应用'

    const token = getToken()
    const isLoggedIn = !!token

    // 2. 已登录用户访问登录页 → 直接跳到首页(避免重复登录)
    if (to.path === '/login' && isLoggedIn) {
    next({ path: '/' })
    return
    }

    // 3. 白名单内的路由,直接放行
    if (isInWhitelist(to.path)) {
    next()
    return
    }

    // 4. 未登录 + 非白名单 → 拦截,重定向到登录页,并带上「想去的地址」
    if (!isLoggedIn) {
    next({
    path: '/login',
    query: { redirect: to.fullPath } // 关键:记住用户想去哪
    })
    return
    }

    // 5. 已登录且不是访问登录页,放行
    next()
    })

    export default router

    // utils/auth.js – token 存取工具(示例)
    const TOKEN_KEY = 'my_app_token'

    export function getToken() {
    return localStorage.getItem(TOKEN_KEY)
    }

    export function setToken(token) {
    localStorage.setItem(TOKEN_KEY, token)
    }

    export function removeToken() {
    localStorage.removeItem(TOKEN_KEY)
    }

    // views/Login.vue – 登录成功后,跳回 redirect 或首页
    import { useRouter, useRoute } from 'vue-router'
    import { setToken } from '@/utils/auth'

    export default {
    setup() {
    const router = useRouter()
    const route = useRoute()

    async function handleLogin() {
    // 模拟登录接口
    const res = await api.login({ username, password })
    setToken(res.data.token)

    // 重点:有 redirect 就跳回去,否则去首页
    const redirect = route.query.redirect || '/'
    router.push(redirect)
    }

    return { handleLogin }
    }
    }


    八、常见踩坑

    场景问题建议
    死循环 重定向到登录页时未排除登录页本身,导致在白名单判断和登录页重定向间来回跳 把 /login 放入白名单,或在重定向前明确判断
    忘记调用 next() 守卫里既没放行也没重定向 每个分支都要 next(),且只调用一次
    重复 next() 同一分支里调用多次 next() 每个分支调用一次后 return,避免后续再执行
    在 beforeEach 里请求用户信息 每次路由切换都请求,性能差、体验差 在登录成功后请求一次,或在主布局中请求,守卫只做 token 有无判断

    九、总结

    • 登录态:用 token 表示,存 localStorage,由后端签发和校验。
    • 白名单:不用登录也能访问的路由,用数组 + includes/some 判断。
    • 重定向:未登录时跳到 /login,并用 query.redirect 保存目标地址,登录成功后跳回。
    • beforeEach:只做 token 判断、白名单判断、简单重定向和放行;不在这里发请求、不做复杂业务、不重复调用 next()。
    • 调用 next():每个分支都要有,且只调用一次,用 return 保证逻辑清晰。

    🔍 本系列专栏导航

    一、《路由与布局扫盲篇:Vue Router 实战 | 动态路由、嵌套路由与多级菜单》 二、《路由与布局扫盲篇:登录态与路由守卫 | token 校验、白名单、重定向》

    👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~


    学习本就是一场持久战,不需要急着一口吃成胖子。哪怕今天你只记住了一点点,这都是实打实的进步。

    后续我还会继续用这种大白话、讲实战方式,带大家扫盲更多前端基础。

    关注我,不迷路,咱们把那些曾经模糊的知识点,一个个彻底搞清楚。

    如果你觉得这篇内容对你有帮助,不妨点赞+收藏,下次写代码卡壳时,拿出来翻一翻,比搜引擎更靠谱。

    我是 Eugene,你的电子学友,我们下一篇干货见~

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 路由与布局扫盲篇:登录态与路由守卫 | token 校验、白名单、重定向
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!