当前位置:首页 » 《随便一记》 » 正文

vue项目中实现用户登录角色鉴权,不同的用户登录展示不同的菜单栏

25 人参与  2023年05月03日 12:25  分类 : 《随便一记》  评论

点击全文阅读


实现的效果如下:

用admin账号登录展示

 用xiaoxiao账号登录:

 并且在xiaoxiao登录的系统中,手动在地址栏输入'/user',请求admin用户才会显示的用户管理页,页面不会展示。

实现思路如下:

1.用户登录,后端返回的data中有菜单数据,把菜单数据存储在vuex中,在侧边栏组件中去获取到存储在vuex中的菜单数据,根据数据动态生成侧边栏。

本项目我是用Mock模拟的数据,后端返回的接口数据如下图:

import Mock from 'mockjs'export default {  getMenu: config => {    const { username, password } = JSON.parse(config.body)    // 先判断用户是否存在    // 判断账号和密码是否对应    if (username === 'admin' && password === 'admin') {      return {        code: 20000,        data: {          menu: [            {              path: '/home',              name: 'home',              label: '首页',              icon: 's-home',              url: 'Home.vue'            },            {              path: '/mall',              name: 'mall',              label: '商品管理',              icon: 'video-play',              url: 'Mall.vue'            },            {              path: '/user',              name: 'user',              label: '用户管理',              icon: 'user',              url: 'User.vue'            },            {              label: '其他',              icon: 'location',              children: [                {                  path: '/page1',                  name: 'page1',                  label: '页面1',                  icon: 'setting',                  url: 'PageOne.vue'                },                {                  path: '/page2',                  name: 'page2',                  label: '页面2',                  icon: 'setting',                  url: 'PageTwo.vue'                }              ]            }          ],          token: Mock.Random.guid(),          message: '获取成功'        }      }    } else if (username === 'xiaoxiao' && password === 'xiaoxiao') {      return {        code: 20000,        data: {          menu: [            {              path: '/home',              name: 'home',              label: '首页',              icon: 's-home',              url: 'Home.vue'            },            {              path: '/video',              name: 'video',              label: '商品管理',              icon: 'video-play',              url: 'Mall.vue'            }          ],          token: Mock.Random.guid(),          message: '获取成功'        }      }    } else {      return {        code: -999,        data: {          message: '密码错误'        }      }    }  }}

在store/tab.js的state中定义一个menu数据用来存储后端返回的菜单栏数据,在mutations中定义一个setMenu方法,在登录成功的时候调用该方法,把后端返回的数据存入menu中

export default {    state:{        //菜单栏数据        menu:[]    },    mutations:{        // 设置menu的数据        setMenu(state,val){            state.menu = val        },    }}

在Login.vue组件中,点击登录调用后端接口,拿到后端返回的数据

//登录        submit(){            this.$refs.form.validate((valid) => {                if(valid){                    getMenu(this.form).then(({ data }) => {                        console.log(data)                        if(data.code === 20000){                            //获取菜单的数据存入store中                            this.$store.commit('setMenu',data.data.menu)                                                    }else{                            this.$message.error(data.data.message)                        }                    })                }            })        }

在 CommonAside.vue中动态计算menuData,然后根据menuData生成菜单栏结构

这样就实现了不同账号登录展示不同的侧边栏。但是,当我们在地址栏中手动输入一些路径,仍能够访问到。比如,在xiaoxiao登录的系统中,输入'/user'仍然显示。原因是项目中的路由表是写死了,就像router/index.js中的注释掉的这部分内容这样:

 

 因此,接下来我们要做得就是利用router.addRoute方法,把这部分内容变成动态的。

代码如下:

还是在store/tab.js中

定义动态添加路由的方法,遍历存储在state中的menu数据,把它从这样

          menu: [            {              path: '/home',              name: 'home',              label: '首页',              icon: 's-home',              url: 'Home.vue'            },            {              path: '/mall',              name: 'mall',              label: '商品管理',              icon: 'video-play',              url: 'Mall.vue'            },            {              path: '/user',              name: 'user',              label: '用户管理',              icon: 'user',              url: 'User.vue'            },            {              label: '其他',              icon: 'location',              children: [                {                  path: '/page1',                  name: 'page1',                  label: '页面1',                  icon: 'setting',                  url: 'PageOne.vue'                },                {                  path: '/page2',                  name: 'page2',                  label: '页面2',                  icon: 'setting',                  url: 'PageTwo.vue'                }              ]            }          ]

变成和注释掉的那部分一样,然后调用router.addRoute()把内容添加到路由表中。

 实现代码如下:

export default {    state:{        //菜单栏数据        menu:[]    },    mutations:{        // 设置menu的数据        setMenu(state,val){            state.menu = val        },        //动态注册路由        addMenu(state,router){            if(state.menu.length == 0 ) return            //组装动态路由的数据            const menuArray = []            state.menu.forEach(item => {                if(item.children){                    item.children = item.children.map(childItem => {                        childItem.component = () => import(`../views/${childItem.url}`)                        console.log(childItem.component)                        return childItem                    })                    console.log(item.children)                    menuArray.push(...item.children)                }else{                    item.component = () => import(`../views/${item.url}`)                    menuArray.push(item)                }                console.log(menuArray,'menuArray')                //路由的动态添加                menuArray.forEach(item => {                    router.addRoute('main',item)                })            })        }    }}

因为要用到router的api,所以,在定义addMenu方法的时候要把路由实例作为参数传进来。

在Login.vue组件中,登录成功调用addMenu方法:

//登录        submit(){            this.$refs.form.validate((valid) => {                if(valid){                    getMenu(this.form).then(({ data }) => {                        console.log(data)                        if(data.code === 20000){                            //token信息存入cookie用于不同页面间的通信                            Cookie.set('token', data.data.token)                            //获取菜单的数据存入store中                            this.$store.commit('setMenu',data.data.menu)                                                        //动态添加路由表中的数据                            this.$store.commit('addMenu',this.$router)                            //跳转到首页                            this.$router.push('/home')                        }else{                            this.$message.error(data.data.message)                        }                    })                }            })        }

经过上边操作路由表中的数据已经成功动态生成了,接下来设置路由拦截:

在router/index.js中:

//添加前置导航守卫router.beforeEach((to, from, next) => {    // 判断token存不存在    const token = Cookie.get('token')    // token不存在,说明当前用户是未登录,应该跳转至登录页    if(!token && to.name !== 'login'){        next({name:'login'})    }else if (token && to.name === 'login'){  //token存在,说明用户已经登录了       next({name:'home'})    }else{        next()    }})

这样就实现了动态路由,但是存在两个问题:

1.刷新页面,vuex中的menu会初始化为[]

 解决方法:作vuex的持久化,可参考我另外一篇博客:

vuex持久化存储插件vuex-persistedstate_奋进的大美的博客-CSDN博客

2.刷新页面,路由表数据也会重置

解决方法:

在main.js中调用addMenu方法:


点击全文阅读


本文链接:http://zhangshiyu.com/post/60414.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1