Vue permission routing [menu permission / button permission control]

Posted by danrah on Tue, 15 Feb 2022 04:56:46 +0100

preface

Completed the railway background management system for half a year years ago. The overall business of the system is relatively complex. This is also a complete system practice from 0 to 1 in my company. I stepped on many pits and learned a lot in the process of making this system</ br>

Not long after finishing this system, another system came. I was ashamed that I didn't summarize it in time! In fact, most of the basic frameworks of the background management system we are working on are the same. The background management system mainly focuses on role permission management, button permission management and menu management. Other businesses are mainly expanded on this basis, and finally form a business compliant background management system

Since our projects adopt Vue technology stack, this article also explains how Vue manages permissions. There are colored eggs at the end!

Permission authorization login

Any background management system starts with login and returns the user's basic information and token after login.

Token: it is stored in sessionstronge / localstrong, and then added to the request header of the encapsulated Axios. Each request carries a token Basic user information

After logging in successfully, you have to do many things at the same time, and the specific business is treated in detail. After successful login, the background management system will request the menu permission interface of the current user to obtain the user's accessible route (dynamic route). After successful acquisition, Vue Router cannot be used directly and must be parsed into a format recognized by Vue Router

Sign in

    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true;
          login(this.loginForm)
            .then(res => {
              if (res.code === 200) {
                // Store token
                sessionStorage.setItem("tokens", res.data.token);
                // Trigger Vuex to load the menu to get the current user and parse the route
                store.dispatch("setMenuList");
                this.$message({
                  message: "Login successful",
                  type: "success",
                  duration: 1000
                });
                this.$router.replace({ path: "/dashboard" });
              }
            })
            .catch(() => {
              this.loading = false;
            });
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    }

Get the current user menu and resolve the route

After logging in successfully, this paper uses Vuex to obtain the current user menu and analyze the route.

store.dispatch("setMenuList");

/*
 * @Description: 
 * @Author: ZhangXin
 * @Date: 2021-02-02 16:10:59
 * @LastEditTime: 2021-02-23 23:03:30
 * @LastEditors: ZhangXin
 */
// getMenu parsing background route
import { getMenu } from '../../utils/getMenu'
// Introduce routing and static routing
import router, { constantRoutes } from '../../router/index'
const state = {
  routerType: '',
  // Menu routing
  meunList: []
}

const mutations = {
  SET_ROUTER_TYPE(state, type) {
    state.routerType = type
  },
  SET_ROUTER_MENULIST(state, list) {
    // Static route + dynamic route merge complete route
    const array = constantRoutes.concat(list)
    state.meunList = array
    router.options.routes = array
    router.addRoutes([...array])
  }
}

const actions = {
  setMenuList({ commit, state }) {
    // Receive the returned route array
    return new Promise((resolve, reject) => {
      getMenu().then(res => {
        commit('SET_ROUTER_TYPE', '')
        commit('SET_ROUTER_MENULIST', res)
        resolve(res)
      })
    })
  }
}
export default {
  state,
  mutations,
  actions
}

Analyze the back-end return route (focus)

The encapsulated route returned from the back-end is mainly used in Vuex.

/*
 * @Description: 
 * @Author: ZhangXin
 * @Date: 2021-02-02 16:03:48
 * @LastEditTime: 2021-02-23 23:09:02
 * @LastEditors: ZhangXin
 */
import Layout from '@/layout'
import {getUserAuthMenu} from '@/api/user'



/**
 * @description: Parse the menu tree returned from the backend
 * @param {*} data Routing tree returned from the backend
 * @param {*} arr menu
 * @return {*}
 */
function tree(data, arr) {
  data.forEach((datas, index) => {
    arr.push({
      path: datas.path,
      name: datas.name,
      types: datas.types,
      hidden: datas.hidden == 'true' ? true : false,
      // At that time, the hole was trampled
      component: datas.component === 'Layout' ? Layout : resolve => require([`@/views/${datas.component}.vue`], resolve),
      meta: {
        title: datas.meta.title,
        icon: datas.meta.icon,
        // Used to store button permissions
        button: datas.meta.button
      },
      //  redirect: datas.redirect,
      id: datas.id,
      // Sub route
      children: []
    })

    if (datas.children) {
      const childArr = tree(datas.children, [])
      arr[index].children = childArr
    }
  })
  return arr
}


/**
 * @description: Get the menu of the currently logged in user
 * @param {*}
 * @return {*}
 */
export function getMenu() {
  return new Promise(function (resolve, reject) {
    getUserAuthMenu().then(res => {
      if(res.code === 200){
      const datas = res.data
      // Call tree to parse the tree returned from the backend
      resolve(tree(datas, []))
      }

    })
  })
}

Back end receive routing format

Real menu tree received by the front end

Page refresh, route loss

So far, Vue dynamic permission control has been realized. Don't be happy too early. Ha ha, as soon as the page is refreshed, the page enters page 404.

Why?

Because the data stored in Vuex will be cleared as soon as the page is refreshed. Of course, if the current route cannot be found, it will enter page 404

How to deal with it?

1, The static and dynamic complete routes can be stored in sessionstrone / localstrong, and then when the page is refreshed, through the global entry file app In the life cycle created of Vue, route = sessionstrong / localstrong is saved into the complete route. When the page is refreshed, it will reload the complete route. 2, If you use the Vuex.app and Vuex.user menus to get the files, you can In the life cycle created of Vue, execute Vuex Action again to reload the user menu

I'm directly on the app In the Vue life cycle created, Vuex is executed again for loading and parsing without other operations. Of course, specific business is treated on a case by case basis.

<template>
  <div id="app">
    <router-view v-if="isRouterAlive" />
  </div>
</template>

<script>
import store from "@/store";
export default {
  name: "App",
  provide() {
    return {
      reload: this.reload
    };
  },
  data() {
    return {
      isRouterAlive: true
    };
  },
  methods: {
    reload() {
      this.isRouterAlive = false;
      this.$nextTick(() => (this.isRouterAlive = true));
    }
  },
  created() {
      //As long as the page is refreshed, the routing tree will be reloaded to ensure that the routing will not lose data
	  store.dispatch("setMenuList");
  }
};
</script>

summary

Core idea

1. Define the service routing format that conforms to the current project, and the front and back ends will receive and deliver according to this 2. The front end parses the dynamic route returned by the back end, generates a Vue Router recognizable format, and finally splices the complete route 3. Refresh route loss processing

Button permission control

1. The current component route carries the available button permissions, which are stored in the array, and whether to display them is judged by v-if 2. When logging in, obtain the button permissions of the whole system separately, store all the obtained buttons in an array and put them into the global, and then judge whether to display them through v-if 3. ............