Vue-based front-end permission management

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

Tags: Front-end

Posted by elgordo1960 on Wed, 21 Dec 2022 14:42:33 +1030