基于vue,vue-router, vuex及addRoutes进行权限控制问题

<p style="text-align: center">

基于vuex,vue-router,vuex的权限控制教程,完整代码地址见 nofollow" href="https://github.com/linrunzheng/vue-permission-control">https://github.com/linrunzheng/vue-permission-control

接下来让我们模拟一个普通用户打开网站的过程,一步一步的走完整个流程。

首先从打开本地的服务localhost:8080开始,我们知道打开后会进入login页面,那么判断的依据是什么。

首先是token。

没有登陆的用户获取不到token的,而登陆后的角色我们会将token存到local或者seesionStorage 因此,根据当前有没有token即可知道是否登陆。

为了存取token并且方便我们操作,可以配和vuex实现

rush:js;"> /* state.js */ export default { get UserToken() { return localStorage.getItem('token') },set UserToken(value) { localStorage.setItem('token',value) } } /* mutation.js */ export default { LOGIN_IN(state,token) { state.UserToken = token },LOGIN_OUT(state) { state.UserToken = '' } }

拦截的判断

没有token进入需要权限的页面:redirect到login页面

由于我们路由是动态挂载的,包括 ' ' 和404,所以当匹配不到路由时,也重定向到login

{ if (!store.state.UserToken) { if ( to.matched.length > 0 && !to.matched.some(record => record.Meta.requiresAuth) ) { next() } else { next({ path: '/login' }) } } })

好了,此时用户打开localhost:8080,认匹配的是''路径,此时我们并没有挂载路由,也没有token,所以来到了login。

输入用户名密码后,有token了,通过store触发* commit('LOGIN_IN')* 来设置token。

但是还是没有路由,目前最开始只有login路由

rush:js;"> /* 初始路由 */ export default new Router({ routes: [ { path: '/login',component: Login } ] }) /* 准备动态添加的路由 */ export const DynamicRoutes = [ { path: '',component: Layout,name: 'container',redirect: 'home',Meta: { requiresAuth: true,name: '首页' },children: [ { path: 'home',component: Home,name: 'home',Meta: { name: '首页' } } ] },{ path: '/403',component: Forbidden },{ path: '*',component: NotFound } ]

我们要根据当前用户的token去后台获取权限。

由于权限这块逻辑还挺多,所以在vuex添加一个permission模块来处理权限。

为了判断是已有路由列表,需要在vuex的permission模块存一个state状态permissionList用来判断,假如permissionList不为null,即已经有路由,如果不存在,就需要我们干活了。

{ if (!store.state.UserToken) { ... } else { /* 现在有token了 */ if (!store.state.permission.permissionList) { /* 如果没有permissionList,真正的工作开始了 */ store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } else { if (to.path !== '/login') { next() } else { next(from.fullPath) } } } })

来看一下 store.dispatch('permission/FETCH_PERMISSION') 都干了什么

v.path === '') let children = MainContainer.children children.push(...routes) /* 生成左侧导航菜单 */ commit('SET_MENU',children) setDefaultRoute([MainContainer]) /* 初始路由 */ let initialRoutes = router.options.routes /* 动态添加路由 */ router.addRoutes(DynamicRoutes) /* 完整的路由表 */ commit('SET_PERMISSION',[...initialRoutes,...DynamicRoutes]) } }

首先,await fetchPermission()获取后台给的权限数组,格式大概如下

rush:js;"> { "code": 0,"message": "获取权限成功","data": [ { "name": "订单管理","children": [ { "name": "订单列表" },{ "name": "生产管理","children": [ { "name": "生产列表" } ] },{ "name": "退货管理" } ] } ] }

其次根据我们写好的路由数组,进行对比,过滤得到我们要的路由

rush:js;"> /* 这里是我们写好的需要权限判断的路由 */ const dynamicRoutes = [ { path: '/order',component: Order,name: 'order-manage',Meta: { name: '订单管理' },children: [ { path: 'list',name: 'order-list',component: OrderList,Meta: { name: '订单列表' } },{ path: 'product',name: 'product-manage',component: ProductManage,Meta: { name: '生产管理' },children: [ { path: 'list',name: 'product-list',component: ProductionList,Meta: { name: '生产列表' } },{ path: 'review',name: 'review-manage',component: ReviewManage,Meta: { name: '审核管理' } } ] },{ path: 'returnGoods',name: 'return-goods',component: ReturnGoods,Meta: { name: '退货管理' } } ] } ] export default dynamicRoutes

为了对比,我写好了一个递归函数,用name和Meta.name进行对比 ,根据这个函数就可以得到我们想要的结果

{ userRouter.forEach((item,index) => { if (item.name === v.Meta.name) { if (item.children && item.children.length > 0) { v.children = recursionRouter(item.children,v.children) } realRoutes.push(v) } }) }) return realRoutes }

得到过滤后的数组后,加入到path为''的children下面

rush:js;"> { path: '',Meta: { name: '首页' } }, ... ] }

这个时候,path为''的children就是我们左侧的导航菜单了,存到state的sidebarMenu待用。加入到children后,这时DynamicRoutes就可以加入到路由了。

rush:js;"> /* 动态添加路由 */ router.addRoutes(DynamicRoutes) /* 初始路由 */ let initialRoutes = router.options.routes /* 合并起来,就是完整的路由了 */ commit('SET_PERMISSION',...DynamicRoutes])

路由添加完了,也就是action操作完毕了,即可在action.then里面调用 next({ path: to.path })进去路由,这里要注意,next里面要传参数即要进入的页面的路由信息,因为next传参数后,当前要进入的路由会被废止,转而进入参数对应的路由,虽然是同一个路由,这么做主要是为了确保addRoutes生效了。

进入路由后,要开始生成左侧菜单,之前我们已经存到sidebarMenu了,现在需要做的只是递归生成菜单而已,虽然用了element的导航菜单,但是为了递归路由,还需要自己封装一下。这里核心的地方是组件的name,在组件里面有children的地方,又再次使用自己,从而遍历整个tree结构的路由。

rush:js;"> Meta.name}}

刷新页面后,根据我们router.beforeEach的判断,有token但是没permissionList,我们是会重新触发action去获取路由的,所以无需担心。但是导航菜单active效果会不见。不过我们已经把el-menu-item的key设置为路由的name,那么我们只要在刷新后,在afterEach把当前路由的name赋值给el-menu default-active即可。同理,在afterEach阶段获取所有matched的路由,即可实现面包屑导航。

{ next({ path: to.path }) }) } ... router.afterEach((to,next) => { var routerList = to.matched store.commit('setCrumbList',routerList) store.commit('permission/SET_CURRENT_MENU',to.name) })

退出登陆后,需要刷新页面,因为我们是通过addRoutes添加的,router没有deleteRoutes这个api,所以清除token,清除permissionList等信息,刷新页面是最保险的。

最后还有一点,每次请求得带上token,可以对axios封装一下来处理

{ axios .get(url,options) .then( res => { var response = res.data if (response.code === 0) { resolve(response.data) } else { Message.warning(response.message) /* reject(response.message) */ } },error => { if (error.response.status === 401) { Message.warning({ message: '登陆超时,请重新登录' }) store.commit('LOGIN_OUT') window.location.reload() } else { Message.error({ message: '系统异常' }) } reject(error) } ) .catch(e => { console.log(e) }) }) } export default instance

总结

以上所述是小编给大家介绍的基于vue,vue-router,vuex及addRoutes进行权限控制问题。编程之家 jb51.cc 收集整理的教程希望能对你有所帮助,如果觉得编程之家不错,可分享给好友!感谢支持

相关文章

可以通过min-width属性来设置el-table-column的最小宽度。以...
yarn dev,当文件变动后,会自动重启。 yanr start不会自动重...
ref 用于创建一个对值的响应式引用。这个值可以是原始值(如...
通过修改 getWK005 函数来实现这一点。这里的 query 参数就是...
&lt;el-form-item label=&quot;入库类型&quot; ...
API 变动 样式类名变化: 一些组件的样式类名有所变动,可能需...