This time I will show you how to use vue, vue-router, vuex and addRoutes for permission control. What are the precautions?What are the following? This is a practical case, let’s take a look at it.
Permission control tutorial based on vuex, vue-router, vuex, the complete code address can be found at https://github.com/linrunzheng/vue- permission-control
Next, let us simulate the process of an ordinary user opening the website and walk through the entire process step by step.
First start by opening the local service localhost:8080. We know that after opening, we will enter the login page, so what is the basis for judgment.
First is the token.
Users who are not logged in will not be able to obtain the token. For characters after logging in, we will save the token to local or seesionStorage. Therefore, you can know whether to log in or not based on whether there is a token currently.
In order to access the token and facilitate our operation, it can be combined with vuex to achieve
/* 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 = '' } }
Interception judgment
No token Enter the page that requires permissions: redirect to the login page
Since our routes are dynamically mounted, including ' ' and 404, when no route is matched, we will also redirect to login
router.beforeEach((to, from, next) => { if (!store.state.UserToken) { if ( to.matched.length > 0 && !to.matched.some(record => record.meta.requiresAuth) ) { next() } else { next({ path: '/login' }) } } })
Okay, now the user opens localhost:8080, and the default matching path is ''. At this time, we have not mounted the route and have no token, so we come to login.
After entering the username and password, there is a token. Trigger *commit('LOGIN_IN')* through the store to set the token.
But there is still no route. At present, there is only the login route.
/* 初始路由 */ 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 } ]
We need to go to the background to obtain permissions based on the current user's token.
Since there is quite a lot of logic in permissions, a permission module was added to vuex to handle permissions.
In order to determine whether there is an existing route list, you need to save a state permissionList in the permission module of vuex for judging. If the permissionList is not null, that is, there is already a route. If it does not exist, we need to work. .
router.beforeEach((to, from, next) => { 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) } } } })
Let’s take a look at what store.dispatch('permission/FETCH_PERMISSION') does
actions: { async FETCH_PERMISSION({ commit, state }) { /* 获取后台给的权限数组 */ let permissionList = await fetchPermission() /* 根据后台权限跟我们定义好的权限对比,筛选出对应的路由并加入到path=''的children */ let routes = recursionRouter(permissionList, dynamicRouter) let MainContainer = DynamicRoutes.find(v => 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]) } }
First, await fetchPermission() gets the permission array given by the background. The format is roughly as follows
{ "code": 0, "message": "获取权限成功", "data": [ { "name": "订单管理", "children": [ { "name": "订单列表" }, { "name": "生产管理", "children": [ { "name": "生产列表" } ] }, { "name": "退货管理" } ] } ] }
Secondly, based on the route array we wrote, compare and filter to get the route we want
/* 这里是我们写好的需要权限判断的路由 */ 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
For comparison, I wrote a recursive function, using name and meta .name for comparison, we can get the result we want based on this function
/** * * @param {Array} userRouter 后台返回的用户权限json * @param {Array} allRouter 前端配置好的所有动态路由的集合 * @return {Array} realRoutes 过滤后的路由 */ export function recursionRouter(userRouter = [], allRouter = []) { var realRoutes = [] allRouter.forEach((v, i) => { 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 }
After getting the filtered array, add it to the children with path ''
{ path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首页' }, children: [ { path: 'home', component: Home, name: 'home', meta: { name: '首页' } }, <!-- 将上面得到的东西加入到这里 --> ... ] }
At this time, path The children of '' are our navigation menu on the left, which are saved to the sidebarMenu of state for later use. After adding to children, DynamicRoutes can be added to the route.
/* 动态添加路由 */ router.addRoutes(DynamicRoutes) /* 初始路由 */ let initialRoutes = router.options.routes /* 合并起来,就是完整的路由了 */ commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])
After the route is added, that is, the action operation is completed, you can call next({ path: to.path }) in action.then to enter the route. Note here that parameters must be passed in next. The routing information of the entered page, because after next passes the parameter, the current route to be entered will be abolished and the route corresponding to the parameter will be entered. Although it is the same route, this is mainly to ensure that addRoutes takes effect.
After entering the routing, we need to start generating the left menu. We have saved it to sidebarMenu before. Now all we need to do is to generate the menu recursively. Although the navigation menu of element is used, for recursive routing, we still need Encapsulate it yourself. The core here is the name of the component. Where there are children in the component, you use yourself again to traverse the routing of the entire tree structure.
<template> <p class="menu-container"> <template v-for="v in menuList"> <el-submenu :index="v.name" v-if="v.children&&v.children.length>0" :key="v.name"> <template slot="title"> <i class="iconfont icon-home"></i> <span>{{v.meta.name}}</span> </template> <el-menu-item-group> <my-nav :menuList="v.children"></my-nav> </el-menu-item-group> </el-submenu> <el-menu-item :key="v.name" :index="v.name" @click="gotoRoute(v.name)" v-else> <i class="iconfont icon-home"></i> <span slot="title">{{v.meta.name}}</span> </el-menu-item> </template> </p> </template> <script> export default { name: 'my-nav', props: { menuList: { type: Array, default: function() { return [] } } }, methods: { gotoRoute(name) { this.$router.push({ name }) } } } </script>
After refreshing the page, according to our router.beforeEach judgment, there is a token but no permissionList. We will re-trigger the action to obtain the route, so there is no need to worry. But the navigation menu active effect will disappear. However, we have set the key of el-menu-item to the name of the route, so we only need to assign the name of the current route to el-menu default-active in afterEach after refreshing. In the same way, breadcrumb navigation can be achieved by obtaining all matched routes in the afterEach stage.
if (!store.state.permission.permissionList) { store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } ... router.afterEach((to, from, 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封装一下来处理
var instance = axios.create({ timeout: 30000, baseURL }) // 添加请求拦截器 instance.interceptors.request.use( function(config) { // 请求头添加token if (store.state.UserToken) { config.headers.Authorization = store.state.UserToken } return config }, function(error) { return Promise.reject(error) } ) /* axios请求二次封装 */ instance.get = function(url, data, options) { return new Promise((resolve, reject) => { axios .get(url, data, 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
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of How to use vue, vue-router, vuex and addRoutes for permission control. For more information, please follow other related articles on the PHP Chinese website!