The idea of ββfront-end permission control is mainly divided into the following directions: πππππ
1. Menu control (navigation sidebar)
The permission data returned by the backend is obtained in the login request, and the frontend dynamically displays the corresponding menu according to the permission data. Click the menu to view the corresponding interface
store.js
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { user: JSON.parse(localStorage.getItem('user') || '[]' }, mutations: { setUser(state, user) { state.user = user // console.log(state.user); localStorage.setItem('user', JSON.stringify(user)) } }, actions: { }, modules: { } })
Aside.vue
<template> <div class="aside"> <el-menu background-color="#00BFFF" text-color="#fff" > <el-submenu v-for="(item,index) in this.menuList " :key="index" class="nav-title" :index="String(index)"> <template slot="title"> <i class="el-icon-location"></i> <span slot="title">{{item.authName}}</span> </template> <el-menu-item v-for="(item,index) in item.children" :key="index" @click="$router.push({ path: item.path, query: { name: item.authName}})">{{item.authName}}</el-menu-item> </el-submenu> </el-menu> </div> </template> <script> // Menu permission control: login to get permission data, cache to Vuex // Take the value from vuex, assign it to the current menulist, and perform v-for traversal on the menulist to display the data import {mapState} from 'vuex'; export default { data(){ return{ menuList:[] } }, methods:{}, mounted(){ this.menuList = this.user.rights console.log(this.menuList,'Menu Permission Data'); }, computed:{ ...mapState(['user']) } } </script> <style lang="less" scoped> .nav-title { & /deep/ i { color: #fff; } .el-menu-item { color: #fff; } } </style>
2. Interface control
The user has not logged in, and manually enters the address in the address bar, and needs to jump to the login interface;
dynamic routing. Dynamically add the current user's route according to the authority;
The user has already logged in, manually type in an address outside the authority, and jump to 404
router.js
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' import Login from '../views/Login.vue' import NotFound from '../views/NotFound.vue' import store from '../store/index' Vue.use(VueRouter) const routerOne = { path: '/menu/one', component: () => import('@/views/Page1.vue') } const routerTwo = { path: '/menu/two', component: () => import('@/views/Page1.vue') } const routerThree = { path: '/menu/three', component: () => import('@/views/Page1.vue') } const routerFour = { path: '/menu/four', component: () => import('@/views/Page1.vue') } const routerFive = { path: '/menu/five', component: () => import('@/views/Page1.vue') } const roleMap = { "/menu/one": routerOne, "/menu/two": routerTwo, "/menu/three": routerThree, "/menu/four": routerFour, "/menu/five": routerFive, } const routes = [ { path: '/', name: 'Home', component: Home, redirect: '/menu/one', children: [] }, { path: '/login', name: 'Login', component: Login }, { path: '*', name: 'NotFound', component: NotFound } ] const router = new VueRouter({ routes }) // Route navigation guard, intercepting illegal jump means router.beforeEach((to, from, next) => { // console.log(from); // console.log(to); if (to.path === '/login') { next(); } else { const token = localStorage.getItem('token'); if (!token) { next('/login'); } else { next(); } } }) //Dynamic routing, after successful login, route matching is dynamically added according to the secondary routing authority export function initDynamicRoutes() { // Dynamically add routing rules console.log(router, 'routing information'); const currentRoutes = router.options.routes let rights = store.state.user.rights; console.log(rights, 'User Routing Permissions'); rights.forEach(item => { // console.log(item,'level one permission menu'); // The path corresponding to the current user's routing authority is mapped to the corresponding routing rule, and push ed to the current routing children item.children.forEach(item => { const temp = roleMap[item.path] // According to the permission data of login, add meta to the current route as the source data of the corresponding permission temp.meta = item.rights currentRoutes[0].children.push(temp) }) }) router.addRoutes(currentRoutes) } export default router
3. Button control
In the interface of a certain menu, display the operable buttons according to the permission data, such as adding, deleting, modifying and checking
permission.js
import Vue from "vue"; // According to the permission data of login, add meta to the current route as the source data of the corresponding permission. // Use a custom command to write an action to determine the current user's permission for this button. If the login permission data does not find the action of the custom command, it means that there is no permission // Disable or delete operations without permission import router from '../router/index' Vue.directive('permission', { inserted(el, binding) { // console.log(el, 'Get the current element'); // console.log(binding, 'The content after the current element'); // action: Manually insert the permissions owned by the current user const action = binding.value.action const effect = binding.value.effect // Determine the permissions of the current user among the components corresponding to the current route console.log(router.currentRoute); const meta = router.currentRoute.meta // console.log(meta, 'User permissions corresponding to components under the current route'); // Handwritten and back-end permission data are used for conditional judgment, if no one is found, it means that there is no permission, and relevant operations are performed if (meta.indexOf(action) == -1) { if (effect === 'disabled') { el.disabled = true el.classList.add('is-disabled') } else { el.parentNode.removeChild(el) } } } })
<el-button type="primary" v-permission="{ action: 'add', effect: 'disabled' }" @click="$emit('show')" >Adding goods</el-button > <!-- v-permission Custom command control button permissions -->
4. Control of requests and responses
The user changes the disabled state of the button to the enabled state through an unconventional operation, and the request should be intercepted
http.js
import axios from 'axios' import Vue from "vue"; import router from '../router/index'; Vue.prototype.$http = axios // Mapping of request methods and permissions const actionMap = { "get": "view", "post": "add", "put": "edit", "delete": "delete" } axios.interceptors.request.use((req) => { // console.log(req.url,'request path'); // console.log(req.method,'request method'); if (req.url !== '/login') { // Requests for non-login pages must add token req.headers.Authorization = localStorage.getItem('token') // What kind of operation is obtained according to the request const action = actionMap[req.method] // Requests that are not within the scope of permissions must be blocked // Determine the authority corresponding to the current route // Determine whether the current operation exists in the routing rules of the component const currentRight = router.currentRoute.meta if(currentRight && currentRight.indexOf(action) === -1){ alert('permission denied!') return Promise.reject(new Error('permission denied!!')) } // Determine the behavior of the current request // restful request style (mapping correspondence) // get request view // post request add // put request edit // delete request delete } return req }) // axios.interceptors.response.use((res)=>{ // if(res.data.status === 401){ // router.push('/login') // localStorage.clear() // window.location.reload() // } // return res // })
summary
The implementation of front-end permissions must provide data support from the back-end, otherwise it cannot be realized, and the data structure needs to be communicated and negotiated between the front-end and the back-end
menu control
1. The permission data returned by the login request needs to be shared by multiple components, so use vuex
2. To prevent data loss in the refresh interface, localstorage persistence is required, and setitem getitem is required to synchronize data
interface control
1. Routing navigation guards to prevent skipping the login interface
2. Dynamic routing addRoutes(), the method of routing path and component mapping, so that the routing rules of interfaces without permissions do not exist at all
button control
1. Add the permission of the current user of the meta metadata storage routing rule to the routing rule
2. Obtain the current routing rule and its meta permission metadata through the routing object
3. Whether the custom command control button is deleted or disabled
Request and Response Control
1. Use of request interceptor and response interceptor
2.restful request method mapping, first understand the restful request