跳转到内容

Vue 项目权限控制

刀刀
0字
0分钟
2026/8/16

后端返回路由规则 ※

后端返回权限控制的一般步骤:

  1. 用户登录
  2. 根据用户 userid 获取对应菜单
  3. 规则化格式(根据数据生成合适的路由规则)
  4. 添加动态路由(使用 addRoute
  5. 记录 state

登录获取,格式化数组

新建 perssion.js 文件,用于动态设置路由规则。

获取后端返回的路由数据并格式化。后端返回的数据通常是数组对象,每一项包含 namepathcomponent,值都是字符串。而前端路由 component 需要 import(),因此需要格式化转换。

  • 首先调用接口获取数据
  • 遍历返回的数据数组,格式化 component
  • 动态添加到 router
perssion.js
js
let routeArr = []
function parseRoute(arr) {
  // 返回一个 Promise,后续异步获取数据
  return new Promise((resolve) => {
    arr.forEach((item) => {
      let newItem = Object.assign({}, item)
      let str = item.component
      newItem.component = () => {
        // return require([`@/views${str}`])
        return import(`@/views${str}`)
      }
      routeArr.push(newItem)
    })
    return routeArr
  })
}

if (如果有用户id) {
  // 把数据保存到state中
  axios.get('接口').then((res) => {
    let newArr = parseRoute(res.data.data)
    commit('SET_ROUTES', newArr)
  })
}

注意

  1. 格式化 component 时不能先赋值给字符串变量再放进去,如:

    js
    let str = `@/views${item}`
    return import(str)

    这样会报错。

  2. 低版本不支持 import 时,可使用 require 替代:

    js
    return require([`@/views${str}`])
  3. 格式化时必须用 @/views 拼接,不能后端返回 /views/page 后前端直接采用:

    js
    return import(`@${str}`)

    这样会报错。

导航守卫,动态添加

js
const routerArr = store.state.login.routerArr

router.beforeEach(async (to, from, next) => {
  const token = Cookies.get('token')
  if (token) {
    if (to.path === '/login') {
      next('/')
    } else {
      // 判断是否发请求获取路由规则
      if (routerArr.length == 0) {
        // 没有,掉请求
        const _routerArr = await store.dispatch('getRouter')

        _routerArr.forEach((item) => {
          router.addRoute(item)
        })

        next(to.path) // 继续跳转
      } else {
        // 有了,判断当前用户是否有该路由的权限
        if (to.matched.length !== 0) {
          next() // 有直接跳转
        } else {
          next(from.path) // 没有返回来的页面
        }
      }
    }
  } else {
    // 未登录,判断是否在白名单内
    if (whileList.indexOf(to.path) !== -1) {
      next() // 在白名单内,可以访问
    } else {
      next('/login') // 不在白名单内,返回登录页
    }
  }
})

注意

老版本可使用 addRoutes() 放入路由数组;新版已弃用,只能使用 addRoute() 放入单个路由对象,需遍历数组。

js
let arr = [
  {
    name: 'page',
    path: '/page',
    component: () => import(''),
  },
]

arr.forEach((item) => {
  router.addRoute(item)
})

重置路由

路由守卫中通过路由规则数组长度判断是否已获取数据,若有则不再请求接口。因此用户登出再登录其他账号时,路由规则仍是旧数据。

解决方法:路由规则保存在 Vuex 内,用户登出时将 Vuex 内的路由规则数组清空,并重置路由为初始状态即可。

js
export function resetRoute() {
  const newRouter = new VueRouter({
    routes: initRoutes,
  })
  router.matcher = newRouter.matcher
}

总结

  • 判断用户是否登录:未登录时判断目标页面是否在白名单内,在则跳转,不在则跳转登录页。
  • 用户已登录后判断是否已获取权限数据:若已有,则直接判断目标路由是否有权限,有则跳转,无则提示无权限并返回上一页。
  • 若未获取权限数据,则调用 store 内的 action 函数获取数据,返回 Promise 对象,通过 addRoute 动态添加路由。
  • 用户登出时清空本地存储与 Vuex 内保存的数据数组,获取最新路由状态重新设置路由权限。

按钮权限

获取用户的按钮权限数组,例如:

js
getCode() {
  // ['BUY', 'SALE']
}

页面中获取 state 保存的权限,判断是否存在即可。

前端控制

后端未配置时,前端可在路由数组内通过 meta 属性写死权限,例如:

js
const initRoutes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/home'),
    meta: {
      whileList: ['admin', 'test01'],
    },
  },
]

在前置守卫中通过 to.meta.whileList.includes() 判断当前用户是否有该权限即可。

贡献者

The avatar of contributor named as duyidao duyidao
The avatar of contributor named as 刀刀 刀刀
The avatar of contributor named as v_duyilin v_duyilin
The avatar of contributor named as 平安喜乐 平安喜乐

页面历史

刀刀博客累计访客 人;文档累计访问量共