原文转自:点我

页面权限控制

页面权限控制是什么意思呢?

就是一个网站有不同的角色,比如管理员和普通用户,要求不同的角色能访问的页面是不一样的。如果一个页面,有角色越权访问,这时就得做出限制了。

Vue 动态添加路由及生成菜单这是我写过的一篇文章,
通过动态添加路由和菜单来做控制,不能访问的页面不添加到路由表里,这是其中一种办法。

另一种办法就是所有的页面都在路由表里,只是在访问的时候要判断一下角色权限。如果有权限就让访问,没有权限就拒绝,跳转到 404 页面。

思路:

在每一个路由的 meta 属性里,将能访问该路由的角色添加到 roles 里。用户每次登陆后,将用户的角色返回。然后在访问页面时,把路由的 meta 属性和用户的角色进行对比,如果用户的角色在路由的 roles 里,那就是能访问,如果不在就拒绝访问。

代码示例:

路由信息

  1. routes: [
  2. {
  3. path: '/login',
  4. name: 'login',
  5. meta: {
  6. roles: ['admin', 'user']
  7. },
  8. component: () => import('../components/Login.vue')
  9. },
  10. {
  11. path: 'home',
  12. name: 'home',
  13. meta: {
  14. roles: ['admin']
  15. },
  16. component: () => import('../views/Home.vue')
  17. },
  18. ]

页面控制

  1. // 假设角色有两种:admin 和 user
  2. // 这里是从后台获取的用户角色
  3. const role = 'user'
  4. // 在进入一个页面前会触发 router.beforeEach 事件
  5. router.beforeEach((to, from, next) => {
  6. if (to.meta.roles.includes(role)) {
  7. next()
  8. } else {
  9. next({path: '/404'})
  10. }
  11. })

登陆验证

网站一般只要登陆过一次后,接下来该网站的其他页面都是可以直接访问的,不用再次登陆。
我们可以通过 token 或 cookie 来实现,下面用代码来展示一下如何用 token 控制登陆验证。

 
  1. router.beforeEach((to, from, next) => {
  2. // 如果有token 说明该用户已登陆
  3. if (localStorage.getItem('token')) {
  4. // 在已登陆的情况下访问登陆页会重定向到首页
  5. if (to.path === '/login') {
  6. next({path: '/'})
  7. } else {
  8. next({path: to.path || '/'})
  9. }
  10. } else {
  11. // 没有登陆则访问任何页面都重定向到登陆页
  12. if (to.path === '/login') {
  13. next()
  14. } else {
  15. next(`/login?redirect=${to.path}`)
  16. }
  17. }
  18. })

Vue 动态添加路由及生成菜单

写后台管理系统,估计有不少人遇过这样的需求:根据后台数据动态添加路由和菜单。
为什么这么做呢?因为不同的用户有不同的权限,能访问的页面是不一样的。
在网上找了好多资料,终于想到了解决办法。

动态生成路由

利用 vue-router 的 addRoutes 方法可以动态添加路由。

先看一下官方介绍:

router.addRoutes

  1. router.addRoutes(routes: Array<RouteConfig>)

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

举个例子:

  1. const router = new Router({
  2. routes: [
  3. {
  4. path: '/login',
  5. name: 'login',
  6. component: () => import('../components/Login.vue')
  7. },
  8. {path: '/', redirect: '/home'},
  9. ]
  10. })

上面的代码和下面的代码效果是一样的

  1. const router = new Router({
  2. routes: [
  3. {path: '/', redirect: '/home'},
  4. ]
  5. })
  6.  
  7. router.addRoutes([
  8. {
  9. path: '/login',
  10. name: 'login',
  11. component: () => import('../components/Login.vue')
  12. }
  13. ])

在动态添加路由的过程中,如果有 404 页面,一定要放在最后添加,否则在登陆的时候添加完页面会重定向到 404 页面。

类似于这样,这种规则一定要最后添加。

  1. {path: '*', redirect: '/404'}

动态生成菜单

假设后台返回来的数据长这样

  1. // 左侧菜单栏数据
  2. menuItems: [
  3. {
  4. name: 'home', // 要跳转的路由名称 不是路径
  5. size: 18, // icon大小
  6. type: 'md-home', // icon类型
  7. text: '主页' // 文本内容
  8. },
  9. {
  10. text: '二级菜单',
  11. type: 'ios-paper',
  12. children: [
  13. {
  14. type: 'ios-grid',
  15. name: 't1',
  16. text: '表格'
  17. },
  18. {
  19. text: '三级菜单',
  20. type: 'ios-paper',
  21. children: [
  22. {
  23. type: 'ios-notifications-outline',
  24. name: 'msg',
  25. text: '查看消息'
  26. },
  27. {
  28. type: 'md-lock',
  29. name: 'password',
  30. text: '修改密码'
  31. },
  32. {
  33. type: 'md-person',
  34. name: 'userinfo',
  35. text: '基本资料',
  36. }
  37. ]
  38. }
  39. ]
  40. }
  41. ]

来看看怎么将它转化为菜单栏,我在这里使用了 iview 的组件,不用重复造轮子。

  1. <!-- 菜单栏 -->
  2. <Menu ref="asideMenu" theme="dark" width="100%" @on-select="gotoPage"
  3. accordion :open-names="openMenus" :active-name="currentPage" @on-open-change="menuChange">
  4. <!-- 动态菜单 -->
  5. <div v-for="(item, index) in menuItems" :key="index">
  6. <Submenu v-if="item.children" :name="index">
  7. <template slot="title">
  8. <Icon :size="item.size" :type="item.type"/>
  9. <span v-show="isShowAsideTitle">{{item.text}}</span>
  10. </template>
  11. <div v-for="(subItem, i) in item.children" :key="index + i">
  12. <Submenu v-if="subItem.children" :name="index + '-' + i">
  13. <template slot="title">
  14. <Icon :size="subItem.size" :type="subItem.type"/>
  15. <span v-show="isShowAsideTitle">{{subItem.text}}</span>
  16. </template>
  17. <MenuItem class="menu-level-3" v-for="(threeItem, k) in subItem.children" :name="threeItem.name" :key="index + i + k">
  18. <Icon :size="threeItem.size" :type="threeItem.type"/>
  19. <span v-show="isShowAsideTitle">{{threeItem.text}}</span>
  20. </MenuItem>
  21. </Submenu>
  22. <MenuItem v-else v-show="isShowAsideTitle" :name="subItem.name">
  23. <Icon :size="subItem.size" :type="subItem.type"/>
  24. <span v-show="isShowAsideTitle">{{subItem.text}}</span>
  25. </MenuItem>
  26. </div>
  27. </Submenu>
  28. <MenuItem v-else :name="item.name">
  29. <Icon :size="item.size" :type="item.type" />
  30. <span v-show="isShowAsideTitle">{{item.text}}</span>
  31. </MenuItem>
  32. </div>
  33. </Menu>

代码不用看得太仔细,理解原理即可,其实就是通过三次 v-for 不停的对子数组进行循环,生成三级菜单。

动态菜单这样就可以实现了。

动态路由,因为上面已经说过了用 addRoutes 来实现,现在看看具体怎么做。

首先,要把项目所有的页面路由都列出来,再用后台返回来的数据动态匹配,能匹配上的就把路由加上,不能匹配上的就不加。 最后把这个新生成的路由数据用 addRoutes 添加到路由表里。

  1. const asyncRoutes = {
  2. 'home': {
  3. path: 'home',
  4. name: 'home',
  5. component: () => import('../views/Home.vue')
  6. },
  7. 't1': {
  8. path: 't1',
  9. name: 't1',
  10. component: () => import('../views/T1.vue')
  11. },
  12. 'password': {
  13. path: 'password',
  14. name: 'password',
  15. component: () => import('../views/Password.vue')
  16. },
  17. 'msg': {
  18. path: 'msg',
  19. name: 'msg',
  20. component: () => import('../views/Msg.vue')
  21. },
  22. 'userinfo': {
  23. path: 'userinfo',
  24. name: 'userinfo',
  25. component: () => import('../views/UserInfo.vue')
  26. }
  27. }
  28.  
  29. // 传入后台数据 生成路由表
  30. menusToRoutes(menusData)
  31.  
  32. // 将菜单信息转成对应的路由信息 动态添加
  33. function menusToRoutes(data) {
  34. const result = []
  35. const children = []
  36.  
  37. result.push({
  38. path: '/',
  39. component: () => import('../components/Index.vue'),
  40. children,
  41. })
  42.  
  43. data.forEach(item => {
  44. generateRoutes(children, item)
  45. })
  46.  
  47. children.push({
  48. path: 'error',
  49. name: 'error',
  50. component: () => import('../components/Error.vue')
  51. })
  52.  
  53. // 最后添加404页面 否则会在登陆成功后跳到404页面
  54. result.push(
  55. {path: '*', redirect: '/error'},
  56. )
  57.  
  58. return result
  59. }
  60.  
  61. function generateRoutes(children, item) {
  62. if (item.name) {
  63. children.push(asyncRoutes[item.name])
  64. } else if (item.children) {
  65. item.children.forEach(e => {
  66. generateRoutes(children, e)
  67. })
  68. }
  69. }

所有的代码实现,我都放在 github 上,动态菜单的实现放在这个项目下的 src/components/Index.vuesrc/permission.js 和 src/utils/index.js

  1.  

Vue页面权限控制和动态添加路由的更多相关文章

  1. vue动态添加路由,跳转页面时,页面报错路由重复:vue-router.esm.js?8c4f:16 [vue-router] Duplicate named routes definition: { name: "Login", path: "/login" }

    之前用了一个vue-element-admin做了一个小项目,里面用到了动态添加路由,动态展示侧边栏, 当我切换页面时,控制台总是警告提示路由重复,连续跳转几次页面后,控制台就被这些警告占满了, 于是 ...

  2. vue的动态路由(登录之后拿到动态路由通过addRouters()动态添加路由)

    登录后我们拿到路由动态路由,后端传的数据可能为这个 { path: '/index', meta: { title: '首页', icon: 'icon-shouye', tab_index: , / ...

  3. vue-element-admin登录逻辑,以及动态添加路由,显示侧边栏

    这段时间在研究element-admin,感觉这个库有许多值得学习的地方,我学习这个库的方法是,先看它的路由,顺着路由,摸清它的逻辑,有点像顺藤摸瓜. 这个库分的模块非常清晰,适合多人合作开发项目,但 ...

  4. SAAS云平台搭建札记: (三) AntDesign + .Net Core WebAPI权限控制、动态菜单的生成

    我们知道,当下最火的前端框架,非蚂蚁金服的AntDesign莫属,这个框架不仅在国内非常有名,在国外GitHub上React前端框架也排名第一.而且这个框架涵盖了React.Vue.Angular等多 ...

  5. vue-router 动态添加 路由

    动态添加路由可以用了做权限管理.登录后服务器端返回权限菜单,前端动态添加路由  然后在设置菜单 1.vue-router 有方法router.addRoutes(routes) 动态添加更多的路由规则 ...

  6. 【面试题】Vue2动态添加路由 router.addRoute()

    Vue2动态添加路由 点击打开视频讲解更加详细 场景: 一般结合VueX和localstorage一起使用 router.addRoutes vue-router4后 已废弃:使用 router.ad ...

  7. vue动态添加路由addRoutes之不能将动态路由存入缓存

    在我不知道vue的路由还可以通过addRoutes动态添加时,我只知道vue的路由都是写死在路由表中的,每当跳转时再去加载相应的路由.直到在一个新公司接到需要根据用户的权限显示不同的菜单的需求时才知道 ...

  8. Vue + Element UI 实现权限管理系统 前端篇(十三):页面权限控制

    权限控制方案 既然是后台权限管理系统,当然少不了权限控制啦,至于权限控制,前端方面当然就是对页面资源的访问和操作控制啦. 前端资源权限主要又分为两个部分,即导航菜单的查看权限和页面增删改操作按钮的操作 ...

  9. AntDesignPro的权限控制和动态路由

    最近看了AntDesignPro关于权限控制的官方文档以及自己框架里权限控制的实现,总结一下. 先贴一下官网上关于权限控制的图有利于理解 步骤如下: 判断是否有 AccessToken 如果没有则跳转 ...

随机推荐

  1. Linux服务器架设篇,DHCP服务器的搭建

    学习之前,我们首先来看一个案例: 假如你是一个学校的网络管理老师,需要为教室的70多台电脑配置好网络你会怎么办? 一台一台的给他们配置? 在这里我特别欣赏鸟哥的一句话--"当管理员最大的幸福 ...

  2. 2017蓝桥杯贪吃蛇(C++C组)

    原题: 贪吃蛇长度+-------------------------------------------------+|                                        ...

  3. std::string构造函数

    string(); string (const string& str); string (const string& str, size_t pos, size_t len = np ...

  4. SQL数据类型:nchar,char,varchar,nvarchar 的区别和应用场景

    概括: char:固定长度,存储ANSI字符,不足的补英文半角空格.CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义CHAR(10),那么不论你存储的数据是否达到了10个字节,都要占 ...

  5. java 代码执行cmd 返回值异常 (关于JAVA Project.waitfor()返回值是1)

    关于JAVA Project.waitfor()返回值是1   0条评论 Project.waitfor()返回值是1,找了很久从网上没有发现关于1的说明. 这时对源代码调试了一下,发现Project ...

  6. 跨平台开源密码管理器 KeePassXC

    简介 KeePassXC 是一个开源的跨平台密码管理器.基于 KeePass 二次开发. KeePassXC 可以安全地在本地存储您的密码,配合浏览器插件KeePassXC-Browser可辅助登录. ...

  7. d3限制范围缩放和平移升级到版本4

    感谢您提供帮助以更新下面的代码以在版本4中工作.我已将zoom.behaviour更改为d3.zoom,但我不清楚所需的其他更改.看起来比v3还要复杂! <!DOCTYPE html> & ...

  8. x86汇编之栈与子程序调用

    什么是栈 栈与普通数据结构所说的栈的概念是相似的,遵循后进先出原则.不同的是汇编中所说的栈是一个在内存中连续的保存数据的区域,也即是实际存在的内存区域,进栈和出栈遵循后进先出原则. 在x86架构中,栈 ...

  9. python干货-类属性和方法,类的方法重写

    类属性与方法 类的私有属性 __private_attrs: 两个下划线开头,表明为私有,外部不可用,内部使用时self.__private_attrs. 类的方法 在类的内部,使用 def 关键字来 ...

  10. Python生成一维码

    参考页面 https://pypi.org/project/python-barcode/ 利用python-barcode的库 一.安装python-barcode库 #安装前提条件库 pip in ...