在项目实践中,往往需要用户登录后由后端返回用户的权限,来动态配置路由,vue-router提供了两个方法router.addRoutes(),router.addRoute()可以进行动态路由配置,这里需要注意的是vue-router的options属性存放的是路由配置的信息,并不是响应式的,在动态添加路由规则后,router.options.routes属性不会改变,如果需要更新router.options.routes,则需要手动更改。
下面的代码基于vue-router版本:3.5.1,版本的变化可能会存在一些不同,如使用已废弃的router.addRoutes方法会出现警告。
参考:https://router.vuejs.org/zh/api/#router-addroutes

router.addRoutes 和router.addRoute 新路由规则

  1. router.addRoutes 添加多条新路由规则

    router.addRoutes(routes: Array<RouteConfig>)
    

    动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组

  2. router.addRoute 添加一条新路由规则
    如果该路由规则有 name,并且已经存在一个与之相同的名字,则会覆盖它。

    addRoute(route: RouteConfig): () => void
    

    addRoute方法可用于为现有路由添加子路由规则

    addRoute(parentName: string, route: RouteConfig): () => void
    

在项目实践时,通常在用户登录后获取到用户的权限表,可以将这些数据保存到前端。
下面是一个简单的例子,忽略了很多细节,旨在演示通过路由进行权限控制的方法。

router.beforeEach()中进行全局前置守卫
如果路由地址在白名单中则放行(例外:如果路由是登录并且存在token,重定向到首页)
不在白名单,且无token,重定向到登录页
不在白名单,且有token,放行
  • 在登录时用setTimeout方法模拟异步获取动态路由和token,并保存到localStorage中,调用generateRoutes方法添加路由规则。

  • 在页面手动刷新时,配置的动态路由会消失需要在router.onReady()方法中,再次调用generateRoutes方法。

  • generateRoutes方法遍历动态路由数组,将成员转为RouteConfig,并调用addRoute方法。
    用vue cli搭建了这样一个组件结构

    模板具体什么样式无所谓,这里只做动态路由的展示

  • router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Layout from '../views/Layout.vue'
import { generateRoutes } from '../utils'Vue.use(VueRouter)const constantRoutes = [{path: '/',name: 'Home',component: Layout,redirect: '/index',children: [{path: 'index',component: Home},{path: 'about',name: 'About',component: () => import('../views/About.vue')}]},{path: '/login',name: 'login',component: () => import('../views/Login.vue')},{path: '/404',component: () => import('../views/404Error.vue')}
]const createRouter = () => new VueRouter({mode: 'history',routes: constantRoutes
})const router = createRouter()// 检查是否存在于免登陆白名单
function inWhiteList (toPath) {const whiteList = ['/login', '/404']const path = whiteList.find((value) => {// 使用正则匹配const reg = new RegExp('^' + value)return reg.test(toPath)})return !!path
}router.beforeEach((to, from, next) => {console.group('%c%s', 'color:blue', `${new Date().getTime()}  ${to.path} 的全局前置守卫----------`)console.log('所有活跃的路由记录列表', router.getRoutes())console.groupEnd()const token = localStorage.getItem('token')// 检查to.path是否存在于免登陆白名单if (inWhiteList(to.path)) {if (to.path === '/login' && token) {// 避免重复登录next({ path: '/' })} else {next()}return false}// 判断是否已经登录,未登录则重定向到登录页(通过query传参记录原来的路径)if (!token) {const toPath = to.fullPath !== '/login' ? to.fullPath : '/'next({path: '/login',query: { redirect: toPath }})} else {next()}
})// 在路由完成初始导航时调用,如果有异步操作放置到这里
router.onReady(() => {console.group('%c%s', 'color:red', `${new Date().getTime()}  路由完成初始导航----------`)console.log('添加前-所有活跃的路由记录列表', router.getRoutes())generateRoutes()console.log('添加后-所有活跃的路由记录列表', router.getRoutes())console.groupEnd()
})
// 重置路由
export function resetRouter () {const newRouter = createRouter()router.matcher = newRouter.matcher
}export default router

Login.vue

<template><div><button @click="signIn">登录</button></div>
</template><script>
import { generateRoutes } from '../utils'export default {methods: {signIn () {const routes = [{id: 1,parentId: 0,path: '/sys',component: 'Layout.vue',redirect: '/sys/user'},{id: 2,parentId: 1,path: 'user',component: 'User.vue'}]setTimeout(() => {localStorage.setItem('token', '123456')localStorage.setItem('routes', JSON.stringify(routes))console.log('登录成功')generateRoutes()this.$router.push(this.$route.query.redirect || '/')}, 1000)}}
}
</script>

Layout.vue

<template><div class="layout"><div class="header"><router-link to="/">Home</router-link> |<router-link to="/about">About</router-link> |<router-link to="/sys">Sys</router-link> |<router-link to="/sys/user">User</router-link><button @click="signOut">登出</button></div><router-view/></div>
</template><script>
import { resetRouter } from '../router/index'export default {methods: {signOut () {localStorage.removeItem('token')localStorage.removeItem('routes')resetRouter()console.log('登出后的路由', this.$router.getRoutes())this.$router.push('/login')}}
}
</script>

generateRoutes()

export function generateRoutes () {const _asyncRoutes = JSON.parse(localStorage.getItem('routes'))const routes = _asyncRoutes.map(({ id, parentId, path, component, redirect }) => {const route = { id, parentId, path, redirect }route.component = (resolve) => require([`../views/${component}`], resolve)return route})const asyncRoutes = toTree(routes)asyncRoutes.forEach(route => {router.addRoute(route)})router.addRoute({path: '*',redirect: '/404'})
}

这个有个toTree()用于将数组转成tree,来实现路由嵌套

vue-router的addRoute方法实现权限控制相关推荐

  1. vue动态路由添加,vue-router的addRoute方法实现权限控制,添加根路由和子路由

    addRoute 路由分为静态路由和动态路由 静态路由和动态路由的优缺点 动态路由实现思路: 动态路由遇到的问题与解决方式 动态添加子路由 路由分为静态路由和动态路由 静态路由和动态路由的优缺点 1. ...

  2. 方法级权限控制-基于表达式操作

    Spring Security允许我们在定义URL访问或方法访问所应有的权限时使用Spring EL表达式,在定义所需的访问权限时如果对应的表达式返回结果为true则表示拥有对应的权限,反之则无.Sp ...

  3. 方法级权限控制-@Secured注解使用

    @Secured注解 @Secured注解标注的方法进行权限控制的支持,其值默认为disabled. 示例: @Secured("IS_AUTHENTICATED_ANONYMOUSLY&q ...

  4. 方法级别权限控制-基本介绍与JSR250注解使用

    服务器端方法级权限控制 在服务器端我们可以通过Spring security提供的注解对方法来进行权限控制.Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解.@S ...

  5. Spring Boot Vue Admin 前后端完全分离的权限控制模版

    Spring Boot Vue Admin 简介 提供一套前后端分离的后台权限管理模版,按钮级别的权限控制. 前端 Vue 模板来自 vue-element-admin,其他功能可以根据该项目再进行拓 ...

  6. Vue 动态路由的实现以及 Springsecurity 按钮级别的权限控制

    思路: 动态路由实现:在导航守卫中判断用户是否有用户信息,通过调用接口,拿到后台根据用户角色生成的菜单树,格式化菜单树结构信息并递归生成层级路由表并使用Vuex保存,通过 router.addRout ...

  7. shiro 方法级别细粒度权限控制_Shiro的认证和权限控制

    从类别上分,有两大类: - 认证:你是谁?–识别用户身份. - 授权:你能做什么?–限制用户使用的功能. 权限的控制级别 从控制级别(模型)上分: - URL级别-粗粒度 - 方法级别-细粒度 - 页 ...

  8. 基于vue(element ui) + ssm + shiro 的权限框架

    zhcc 基于vue(element ui) + ssm + shiro 的权限框架 引言 心声 现在的Java世界,各种资源很丰富,不得不说,从分布式,服务化,orm,再到前端控制,权限等等玲琅满目 ...

  9. Vue 学习(十、 Vue Router - 路由插件 和 Vue 的插件原理)

    文章目录 一.Vue Router - 路由插件 1. 安装 Vue Router 2. Vue Router 路由的基本使用 3. 设置 router-link 4. 编程式路由 5. 路由嵌套 6 ...

最新文章

  1. Android 中Message,MessageQueue,Looper,Handler详解+实例
  2. 第一节 Image Processing Toolbox功能介绍
  3. Gin实际编写中间件
  4. 车辆姿态相关的传感器概述
  5. nacos集成dubbo实现远程服务调用多服务端2
  6. android 已经给权限读取照片 还是提示无法读取照片_iPhone无法访问照片,一招教你解决...
  7. GaussDB(DWS)磁盘维护:vacuum full执行慢怎么办?
  8. BGP(边界网关协议)
  9. SPSS Modeler 神经网络实践案例(第十四章)
  10. 【计算机网络】 2019年-中国计算机学会推荐国际学术会议和期刊目录(二)
  11. firewall和企业级的Open ViP服务
  12. http 301 302 303 307 308 傻傻分不清
  13. eve手游php,[Murky Army]EVE无烬星河PVP入门————小队战战术及队伍配置(
  14. 用友u8服务器优化,用友U8erp软件运行的性能优化方案图文教程
  15. codeblocks改变主题背景颜色
  16. Python 人工智能入门须知
  17. 怎么修改PDF文档背景
  18. 淘宝天猫、1688、京东、拼多多原数据api接口
  19. JAVA——34.集合函数-List
  20. 图记 2016.1.5 透明状态栏

热门文章

  1. 微信小程序体验(1):携程酒店机票火车票
  2. 功率放大器设计方案(包含原理图+PCB+BOM表)
  3. micropython 驱动_Micropython 飞控 驱动 3.MPU9250
  4. 数学建模学习(28):又一夜没睡,爆肝整理所有类型matlab求解微分方程+案例实战,学不会来砍我
  5. 某程序员周六给女朋友PS 证件照竟被质疑? 最后交出完美答卷。
  6. C#22GDI+图形图像处理技术
  7. ABP官方文档(四十五)【集成Hangfire】
  8. 1316:数的计数(Noip2001)
  9. 在FC5上使用XMMS2(转)
  10. 谷歌浏览器打开调试模式后刷新页面,页面一直加载问题