preface

Recently, I suddenly saw the background management system written before, and felt that the control of permissions was not well written, so I made a transformation. Here I record the problems and permissions logic encountered in the transformation, hoping to help you a little.

Project preview address: Vue Antd Admin, interested can have a look

Login Permission Control

After clicking login, I used mock mock data, searched in user constant list by user name, returned corresponding user information and token, and then carried token in request header. If no token exists or token is invalid, login is required. Strictly speaking, During login, the password and returned token need to be encrypted and cannot be passed in plain text. This is not done because it is my own project.

After login, the token information and userInfo information are stored in the VUex and Session (of course, you can not save the VUex, depending on the individual). The most important information in the returned information is the roleIds field, which represents the current user has the permission ID

Example Login result:

token: "admin2022012030427", userInfo: { date: "2020-10-13", id: 472467715762, key: "admin", label: "Young people do not speak martial virtue ", location: "Wuhan", password: "123456", position:" mixed yuan Tai Chi door master ", role: "admin", roleIds: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36", roleString: "Admin" skill: "admin" text: "admin" username: "admin"}Copy the code

Request headers carry tokens:

service.interceptors.request.use(config => {
  if (store.getters.token) {
    config.headers['authorization'] = store.getters.token;
  }
  return config;
});
Copy the code

Menu permission Control

Implementation approach

There are two common menu permission control methods, front-end control and back-end control, but it is best to control the front-end, otherwise you want to add a menu must also say and back-end, let him add a menu, and return to the fear of being dominated by the back-end… However, whether it is front-end control or back-end control, it is necessary to get the menu list corresponding to the login user, and then add the route through the addRoutes method of vue-Router.

[‘admin’,’test’] [‘admin’,’test’] [‘admin’,’test’] [‘admin’,’test’] [‘admin’,’test’] [‘admin’,’test’] [‘admin’,’test’] Therefore, each menu is given a corresponding roleId in this modification. Then, the menu corresponding to the current user is obtained by comparing the roleIds in the login and the roleIds in the routing table.

export const asyncRoutes = [ { path: '/', component: Layout, redirect: '/index', hidden: true, children: [ { name: 'index', path: '/index', Component: () => import('@/views/index/index'), meta: {role: 1, title: 'home ', icon: 'dashboard' } }, { name: 'icon', path: '/icon', component: () => import('@/views/icon/index'), meta: { role: 2, title: 'icon', 'icon'}},]Copy the code

beforeEach

We also need a hook for vue-router. BeforeEach this global guard has three arguments :to,from, and next

  • to: the page you want to jump torouteinformation
  • from: of the current pagerouteinformation
  • nextUse this method to resolve the resolve hook, otherwise the page jump will not succeed

For example, if you switch from page A to page B, page A is from, and page B is to

router.beforeEach( (to, from, next) => { const localId = localStorage.getItem('userId'); If (to.name === 'login') {if (localId) {next({... to, replace: true }); } else {// No cache, jump to login page next('/login'); }}});Copy the code

We can separate out beforeEach, create a permission.js file, and then import it in main.js

Access control

This requires careful debugging. If it is judged that the writing is not complete, it is easy to have an endless loop, you can interrupt the debugging point carefully. Permission.js is roughly as follows:

router.beforeEach(async (to, from, next) => { document.title = getPageTitle(to.meta.title); //title Adds the current menu name const isLogin = getCache('TOKEN'); If (to.path == '/login') {// Next next() if (to.path == '/login'); } else { if (! IsLogin) {// If you are not logged in, forcibly jump to login, prevent forcible input address jump to next('/login'); } else { const route = store.state.permission.routes; If (route.length > 0) {next next(); } else {/ / if you do not generate const the userInfo = store. State. The user. The accountInfo; Try {const {roleIds} = userInfo; const accountRoute = await store.dispatch('permission/getRoute', roleIds); Router. AddRoutes (accountRoute); If (from. Path == '/login') {// Next (accountRoute[0].children[0].path); } else { next({ ... to, replace: true }); } } catch (error) { console.log(error); Message. error(' failed to get user information '); next('/login'); }}}}});Copy the code

Get routing menu

Routing table inside can set two kinds of routes, one is not need permission control, such as: login page, 404 page, etc., one is need permission control; Here basRoute is the basic route, asyncRoutes is the route that requires permission control, and here is the permission file of store. The main function is to obtain the route menu according to the roleIds of the logged-in user

import { baseRoute, asyncRoutes } from '@/router'; const state = { routes: [] }; const mutations = { SET_ROUTE(state, route) { state.routes = baseRoute.concat(route); }}; Const Actions = {getRoute({commit}, role) {return new Promise((resolve, resolve) reject) => { let accessedRoutes = []; accessedRoutes = filterAsyncRoute(asyncRoutes, role); commit('SET_ROUTE', accessedRoutes); resolve(accessedRoutes); }); }}; Export function filterAsyncRoute(routes, role) {let arr = []; routes.forEach(item => { const temp = { ... item }; if (hasChildren(temp, role)) { if (temp.children) { temp.children = filterAsyncRoute(temp.children, role); } arr.push(temp); }}); return arr; } role export function hasChildren(route, role) {let roleIds = role.split(','); if (route.meta && route.meta.role) { return roleIds.includes(String(route.meta.role)); } else { return true; } } export default { namespaced: true, state, mutations, actions };Copy the code

Sidebar display

Here we have obtained the corresponding permissions of the user, and the next step is to render it to the sidebar. Here we use recursive traversal, because the antD root directory will not render if there is a div tag, so we use the method of functional components here

<a-menu :mode="mode" :inline-collapsed="! collapsed" theme="dark" :selectedKeys="[$route.path]" :open-keys="openKeys" @openChange="changeOpen" > <template v-for="item in baseRoute"> <menu-item v-if="! item.children && ! item.hidden" :key="item.path :currentRoute="item" /> <template v-else v-for="temp in item.children"> <menu-item v-if="! temp.children" :key="temp.path" :currentRoute="temp" /> <sub-menu v-else :key="temp.path" :currentRoute="temp"></sub-menu> </template> </template> </a-menu>Copy the code
subMenuItem.vue <a-sub-menu :key="props.currentRoute.path"> <template slot="title"> <svg-icon :icon="props.currentRoute.meta.icon" v-if="props.currentRoute.meta.icon"> </svg-icon> <span style="margin-left:16px" class="menu-title">{{ props.currentRoute.meta.title }}</span> </template> <template v-for="item in props.currentRoute.children"> <menu-item v-if="! item.children" :key="item.path" :currentRoute="item" /> <sub-menu v-else :key="item.path" :currentRoute="item" /> </template> </a-sub-menu>Copy the code

Role Management Menu

User and role bindings, roles and menu binding, so will need to modify the roles corresponding to modify menu tree, there’s a little details need to pay attention to, because the tree is to be checked if the parent node, all child nodes will be selected, but in practice, we may need to check the parent node, but only checked a child node, So you have to control it individually, and you have to recurse

Mounted (){if (this.role) {// Echo this. } else { this.checkKeyList = []; Const allRoute = this.getrouteid (data); const allRoute = this.getrouteid (data); const allRoute = this.getrouteid (data); Let roleRoute = this.role. Split (','); // Let roleRoute = this.role. let newRoute = []; ForEach (item => {roleroute. forEach(val => {if (item == val) {newroute.push (val); }}); }); this.checkKeyList = newRoute; Check}, getRouteId(routes, role = null) {const res = []; routes.forEach(item => { if (item.children && item.children.length > 0) { res.push(... this.getRouteId(item.children, item.meta.role)); } else if (item.meta && item.meta.role) { res.push(String(item.meta.role)); } else if (role) { res.push(String(role)); }}); return res; },Copy the code

Page button control

The truth is the same as the menu, but also can give the page button an ID, according to the user information roleIds contain this ID, to control the display and hide, but need to code annotation and documentation is complete, or the next button does not know what the user can see, debugging trouble.

Project description

Vue Antd Admin based on vue-Cli4.x +vuex+ ant-design-Vue development of background management system, including permission management, a variety of layout, skin function, visual drag, large screen display, user multi-role and some other functions, interested can see.

The last

To here, the system background management authority has been completed, the front control authority method has many kinds, can be used according to the specific situation, this time on the admin system modified role authority, users add multiple roles, skin and external chain and other functions, interested can take a look

Other articles

  • Vii. Using VUE + ANTD to build background Management System (Requirements Analysis and Construction)

  • Vi. Remember a Vue3.0 taste \

  • V. Remember to build a VUE project with Webpack once

  • Remember to refactor the project with TS +vuecli4 once

  • Echarts+Amap to achieve the click drilling function

  • Vue keep-alive stomp pit, delete keep-alive cache

\