我司开发一套系统,需要做权限管理,不同角色的用户权限不一样,登录系统看到的东西是不一样的,而且调用接口、登陆是否有效都需要通过一个身份认证token来确认。经过商量,我们做的思路如下:
1、用户先登陆,拿到认证的token,然后存到localStorage中,代码如下:
1 getInfo.post('api-token-auth/',{username:_self.loginData.userCount,password:_self.loginData.password}).then(function(data){ 2 if(data.data.code == 0){ 3 let jwtSession = 'JWT'+' '+data.data.token; 4 localStorage.setItem("checkSession", jwtSession); 5 localStorage.setItem("userInfo", data.data.userinfo.username); 6 localStorage.setItem("routes",JSON.stringify(data.data.userinfo.permissions)) 7 // 路由权限过滤 8 var menuData = JSON.parse(localStorage.getItem('routes')); 9 var localRouter = _self.$router.options.routes 10 for(let i = 0;i<menuData.length;i++){ 11 for(let q = 0;q<localRouter.length;q++){ 12 if(menuData[i].codename == localRouter[q].path.replace(/\//,"")){ 13 localRouter[q].hidden = false; 14 } 15 } 16 } 17 _self.$router.addRoutes(localRouter) 18 _self.$router.push({ path: '/ops_menu_sever_manage'}); 19 } 20 else{ 21 _self.$message({ 22 message: data.data.msg, 23 type: 'warning' 24 }); 25 // _self.$router.push({ path: '/login'}); 26 } 27 28 });
2、我们异步请求用的是axios,所以在配置axios的时候添加了请求拦截器,每次请求的时候,在localStorage中获取我们存的token,并且给请求头部添加一个Authorization请求头,代码如下:
1 // CMDB借口实例 2 export const cmdbAjax = axios.create({ 3 baseURL:cmdbUrl, 4 timeout:10000 5 }) 6 cmdbAjax.interceptors.request.use(function (config) { 7 config.headers.common['Authorization'] = localStorage.getItem('checkSession'); 8 return config; 9 }, function (error) { 10 return Promise.reject(error); 11 });
3、登陆成功,后台会把当前用户所需要的权限全返回给我,拿到之后,也一并存到localStorage里面;
1 localStorage.setItem("routes",JSON.stringify(data.data.userinfo.permissions))
4、开发系统的时候我们正常在本地配好路由,路由表如下:
import Vue from 'vue' import Router from 'vue-router' import layout from '@/views/layout/layout' import devicemanage from '@/views/devicemanage/devicemanage' import devicecontrol from '@/views/devicecontrol/devicecontrol' import deviceadd from '@/views/deviceadd/deviceadd' import deviceupdate from '@/views/deviceupdate/deviceupdate' import login from '@/views/login/login' Vue.use(Router) const router = new Router({ routes: [ { path:'/', component:login, }, { path:'/login', component:login, }, { path: '/deviceadd', component: layout, hidden:true, children: [ { path: '/deviceadd', component:deviceadd, name: 'deviceadd', } ] }, { path: '/deviceupdate', component: layout, hidden:true, children: [ { path: '/deviceupdate', component:deviceupdate, name: 'deviceupdate', } ] }, { path: '/ops_menu_sever_manage', component: layout, hidden:true, children: [ { path: '/devicemanage', component:devicemanage, name: 'devicemanage', meta: { title: '设备管理', icon: 'yingyong' }, } ] }, { path: '/devicecontrol', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '设备监控', icon: 'shezhi' }, }, ] }, { path: '/ops_menu_analytical_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '解析管理', icon: 'jiexi' }, }, ] }, { path: '/ops_menu_basic_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '基础运维', icon: 'yunwei1' }, }, ] }, { path: '/ops_menu_channel_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '频道管理', icon: 'fm' }, }, ] }, { path: '/ops_menu_issued_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '下发管理', icon: 'xiafa' }, }, ] }, { path: '/ops_menu_log_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '日志管理', icon: 'rizhi' }, }, ] }, { path: '/ops_menu_monitor_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '监控管理', icon: 'jiankong' }, }, ] }, { path: '/ops_menu_order_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '工单系统', icon: 'gongdan' }, }, ] }, { path: '/ops_menu_user_manage', component: layout, hidden:true, children: [ { path: 'devicecontrol', component:devicecontrol, meta: { title: '用户管理', icon: 'yonghu2' }, }, ] }, ] }) export default router
4、此时我们获取了后台返回的权限数据,通过this.$router.options.routes获取vue实例中挂在的我们配置好的路由表,循环遍历着两个数组,如果后台返回有权限,那么久吧vue实例中的路由表的hidden属性改为false。
此时已经感觉大功告成,赶紧去页面登录账号试一试。感觉还真行。然后就手贱刷新一把。完了,菜单栏啥也没有了。
我百思不得其解,后来 就赶紧找我的小伙伴商量,找出问题所在了。(在这里要特别感谢我的同事展展给予的无私帮助)
原来特码的,刷新页面之后,vue实例重新创建,路由也会重新加载一遍(也就是把我们配置好的路由表重新挂到了vue实例中),那么我们修改的路由就会消失。此时我已经为自己的无知付出惨痛的时间成本代价。尽然知道问题所在,那么就好解决了,我就赶紧机智的在main.js中添加如下代码:
1 // 路由权限过滤 2 if(localStorage.getItem("checkSession")){ 3 var menuData = JSON.parse(localStorage.getItem('routes')); 4 var localRouter = router.options.routes 5 for(let i = 0;i<menuData.length;i++){ 6 for(let q = 0;q<localRouter.length;q++){ 7 if(menuData[i].codename == localRouter[q].path.replace(/\//,"")){ 8 localRouter[q].hidden = false; 9 } 10 } 11 } 12 router.addRoutes(localRouter) 13 }
赶紧再去重新页面登录一次,发现完美解决问题。再怎么刷新都不会消失了。开心,为自己撒花。然后同事也手贱,特么竟然换了一个不同权限的账号登陆,发现登陆之后的菜单栏竟然和之前登陆的账号完全一样。没有的权限也能看见了,除非刷新一下页面。看见没,重点就在“刷新一下页面”就没事了。此时犯的错误还是和刚才那个是一样的,需要重新创建一下vue实例然后重新挂在一次路由就好了。赶紧去退出登录的时候添加刷新页面代码:
1 loginOut(){ 2 localStorage.removeItem('checkSession'); 3 localStorage.clear(); 4 this.$router.push({path:'/login'}); 5 window.location.reload() 6 }
此时,再去测,完美。
对于vue我也是新手,还有好多地方理解的不到位,希望对阅读本文的人有素帮助,vue大佬们也欢迎尽情吐槽,碰撞才会促进进步。