preface
Front-end control rights are divided into two parts: menu page and button.
Menu permissions
One is the visible menu page: the dom node on the left, and the other is the – one is the accessible menu page: the routing section of the system.
Routing permissions
The interface returns the menu table data format as follows:
[{' name ':' front page ', / / page name 'code' : 'index', 'icon' : 'menu', / / ICONS 'path' : '/ list', 'the orders: 1,' is_hide: 0, 'reserve' : {}, 'components' : [], / / that contains the information button access code' children ': [/ / zi lu by {' name' : 'page 1', 'code' : 'page1', 'icon' : 'menu', 'path' : '/list/page1', 'Orders ': 2, 'is_hide': 0, 'components': {'code':' API '/ add', // 'new', 'the orders: 1, "reserve" : {}}, {' code' : 'API/update', 'name' : 'modify', 'the orders: 1, the' reserve ': {}}...], 'reserve' : {the componentName: 'Page1'}}, {' name ':' page 2 ', 'code' : 'page2', 'icon' : 'menu', 'path' : '/ list/page2', 'the orders: 1,' is_hide: 0, 'components' : [{' code' : 'API/query', 'name' : 'menu query', 'the orders: 1, 'reserve': {} } ], 'reserve': { componentName: 'Page2' } } ] } ]Copy the code
Plan a
In simple terms, the front-end page saves all route configurations, obtains the user’s permission after login, and filters out the route configurations that have the permission, and dynamically adds them to the routes.
router.config.js
/** * Basic route whitelist * @type {*[]} */ export const constantRouterMap = [{path: '/login', Component: Layout, redirect: '/user/login', hidden: true, children: [ { path: 'login', name: 'login', component: () => import(/* webpackChunkName: "User" * / '@ / views/Login')}}], abnormal / * * * * on page / {path: '/ 404', name: '404', component: () => import(/* webpackChunkName: "fail" */ '@/views/Exception/404') } ... ] export const routerMap = [ { path: '/', name: 'index', redirect: '/main', component: BasicLayout, meta: { title: 'front page'}, children: [{path: '/ ac, name:' Main 'component: () = > import (' @ / views/Main'), meta: {title: 'Active management ', keepAlive: true, icon: 'project'}, children: [{path: '/ac/ac_config', name: 'ActivityConfiguration', component: () => import('@/views/Main/ActivityConfiguration'), meta: { title: 'Active Configuration Management ', keepAlive: true}}...]}....]}]Copy the code
After login, request to obtain the menu interface, obtain the menu with permissions, collect the routing code and jump to the home page. Router. js is filtered each time before a route moves to another router. Router. addRoute is used to dynamically add the router to the route.
/** * collectRouterCode (data) {for (const I of data) {if (i.code) { this.routerCodeArr[i.code] = {} if (i.components && i.components.length) { for (const j of i.components) { this.routerCodeArr[i.code][j.code] = true } } } if (i.children && i.children.length) { this.collectRouterCode(i.children) } } },Copy the code
RouterCodeArr: Key is the page code with permissions, which contains the button permissions
{
"index":{},
"page1": {
"api/add":true,
"api/delete": true,
},
"page2":{
"api/query":true
}
....
}
Copy the code
permission.js
// Route whiteList const whiteList = ['login', '403', '404', '500'] router. BeforeEach ((to, from, Next) => {nprogress.start () if (routerCodeArr &&RouterCodearr) {// If (routerCodeArr &&RouterCodearr) (store. State. The login. AddRouters. Length = = = 0) {/ / to access the routing tables dynamically add filterRouter (routerMap) / / dynamic add routing! router.addRoutes(routerMap) store.dispatch('set_add_routers', RouterMap) const redirect = decodeURIComponent (from the query. The redirect | | to. The path) if (to. The path = = = redirect) {/ / hack method Make sure addRoutes completes next({... To, replace: true})} else {// Jump to destination route next({path: Redirect})}} else {// If (whitelist.includes (to.name)) {next()} else {next({path: '/user/login', query: { redirect: to.fullPath } }) NProgress.done() } } } }) router.afterEach(() => { NProgress.done() })Copy the code
The filterRouter method does the filtering
/ function filterRouter (data) {const accessedRouters = data.filter(route => {if) (routerCodeArr[route.name]) { route.meta['auth'] = routerCodeArr[route.name] if (route.children && route.children.length) { route.children = filterAsyncRouter(route.children) } return true } return false }) return accessedRouters }Copy the code
However, as the project grows larger, this static route configuration becomes longer and harder to maintain.
Scheme 2
In simple terms, the route configuration is generated from the menu list returned by the backend.
Router.config. js Whitelist is configured
const constantRouter = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import(/* webpackChunkName: "fail" */ '@/views/error/404')
}
]
Copy the code
permission.js
router.beforeEach((to, from, Next) => {nprogress.start () const hasToken = store.getters. Token /* has token */ if (hasToken) {if (to.path) = = = '/ login') {next () NProgress. Done ()} else {the if (store. Getters. Routers. Length = = = 0) {/ / generate routing configuration Dispatch ('GenerateRoutes'). Then ((routers) => {// dynamically addRoutes router. AddRoutes (routers) const redirect = decodeURIComponent(from.query.redirect || to.path) if (to.path === redirect) { next({ ... To, replace: true})}}). Catch ((err) => {console.log(err) notification.error({message: 'error ', description: 'Failed to request menu information, Please retry '}) store.dispatch('Logout')})} next()}} else {if (whitelist.includes (to.path)) {next()} else {next({path: '/login', query: { redirect: to.fullPath } }) NProgress.done() } } }) router.afterEach(() => { NProgress.done() })Copy the code
The GenerateRoutes method generates the routing configuration
GenerateRoutes ({commit}) {return new Promise(resolve, reject) => {dynamicRouter(). Then ({routers, menus }) => { commit('SET_ROUTERS', routers) resolve(routers) }).catch(error => { reject(error) }) }) }Copy the code
DynamicRouter Obtains routing menu information
/ / export default () => {return new Promise((resolve, resolve, reject) => { const routers = generator(menus) routers.unshift(indexRouter) asyncRouter[0].children = routers resolve({ routers: asyncRouter, menus: res.data.menus }) }) }Copy the code
The generator generates a routing table
/** * Const generator = routerMap => {return RouterMap. map(item => {const currentRouter = {path: item.path, name: item.reserve.componentName, meta: { title: item.name, code: item.code, icon: item.icon, permissions: Item.ponents. Map (item => item.code), // Collect route code Hidden:!! item.is_hide, ... item.reserve }, component: '' } if (item.children && item.children.length > 0) { currentRouter.component = BlankLayout currentRouter.children = generator(item.children) } else { currentRouter.component = () => import(`@/views${item.path}/`) } return currentRouter }) .filter(item => { return ! (! item || item === '') }) }Copy the code
Button permissions
Button permissions control the display of buttons on each page. Do not display this button without permission.
The menu list returned by the interface contains the button permissions of each page, and the display is controlled by instructions after the button permission code is collected.
Directive Definition
*/
import router from '@/router'
import Vue from 'vue'
const auth = Vue.directive('action', {
inserted: function (el, binding, vnode) {
const { value } = binding
const curRouter = router.app.$route
if (curRouter.meta.permissions.length && curRouter.meta.permissions.indexOf(value) > -1) {
} else {
el.parentNode & el.parentNode.removeChild(el) || (el.style.display = 'none')
}
}
})
export default auth
Copy the code
V – auth
<a-button v-action=" API /add "> New </a-button>Copy the code