preface

A year ago, I completed the railway background management system, which I had been working on for half a year. The overall business of the system was relatively complicated, which was also a complete systematic practice when I worked in the company from zero to one. During the process of making this system, I stepped in many pits and learned a lot.

Not long after finishing this system, another system came, and I didn’t summarize it in time. I feel ashamed! In fact, most of the basic framework of the background management system we are doing are the same. The background management system is mainly role permission management, button permission management and menu management. Other businesses are mainly expanded on this basis, and finally constitute a background management system in line with the business.

Since all the projects of our company adopt Vue technology stack, this article also explains how Vue conducts permission management.

There are Easter 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.

  • tokenDeposit:sessionStronge / localStrongeAnd then add it to the packageAxiosEach request carries a token.
  • Basic User Information

After a successful login, you need to do many things at the same time. After a successful login, the background management system will request the menu permission interface of the current user to obtain the accessible route (dynamic route) of the user. After obtaining the successful route, the Vue Router cannot be used directly and must be resolved into a format that can be recognized by the Vue Router.

The login

    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; }}); }Copy the code

Get the current user menu and parse routes

After successful login, Vuex is used to obtain the current user menu and route resolution.

store.dispatch("setMenuList");

/* * @Description: * @Author: ZhangXin * @Date: 2021-02-02 16:10:59 * @LastEditTime: 2021-02-23 23:03:30 * @LastEditors: ZhangXin */
// getMenu parses background routes
import { getMenu } from '.. /.. /utils/getMenu'
// Import routes and static routes
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 route array returned
    return new Promise((resolve, reject) = > {
      getMenu().then(res= > {
        commit('SET_ROUTER_TYPE'.' ')
        commit('SET_ROUTER_MENULIST', res)
        resolve(res)
      })
    })
  }
}
export default {
  state,
  mutations,
  actions
}
Copy the code

Parse the back end return route (emphasis)

The route returned by the parse back end is encapsulated for use 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'



/ * * *@descriptionParse the menu tree * returned from the back end@param {*} Data route tree * returned from the back end@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.// It was dented
      component: datas.component === 'Layout' ? Layout : resolve= > require([`@/views/${datas.component}.vue`], resolve),
      meta: {
        title: datas.meta.title,
        icon: datas.meta.icon,
        // Use to store button permissions
        button: datas.meta.button
      },
      // redirect: datas.redirect,
      id: datas.id,
      / / zi lu by
      children: []})if (datas.children) {
      const childArr = tree(datas.children, [])
      arr[index].children = childArr
    }
  })
  return arr
}


/ * * *@description: Gets the current logged-in user's menu *@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 back end
      resolve(tree(datas, []))
      }

    })
  })
}

Copy the code

Format of the route received by the back-end

The real menu tree received by the front end

The page is refreshed, and routes are lost. Procedure

At this point, we have implemented Vue dynamic permission control, don’t rejoice too soon, ha ha, as soon as the page refresh, the page will enter the 404 page.

Why is that?

Because the data stored in Vuex will be cleared as soon as the page is refreshed, the current route will not be found and the 404 page will be entered.

How do you deal with that?

SessionStronge/localStronge, and then when the page refresh, by creating the lifecycle of the global entry file app.vue. Router = sessionStronge/localStronge; it will reload the complete route when the page is refreshed. 六四屠杀

Two, if it is usedVuexTo get and parse the user menu, then you can file in the global entryApp.vueIs executed again in the created lifecycleVuex ActionTo reload the user menu

I directly created the lifecycle of app.vue and performed Vuex again for loading and parsing without doing anything else. Of course, it depends on the business.

<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 soon as the page is refreshed, the routing tree is reloaded, ensuring that the route does not lose data
	  store.dispatch("setMenuList"); }};</script>

Copy the code

conclusion

core idea

  • 1. Define the business routing format in line with the current project, and the front and back ends receive and transfer according to this format
  • 2. The front-end parses the dynamic route returned by the back-end and generates the routeVue RouterRecognize the format, and finally splice the complete route
  • 3. Refresh the process of route loss


Button permission control

  • 1. The current component route carries the available button permissions, which are stored in the array and judged by V-if whether to display
  • 2. During login, obtain the button permission of the entire system separately, store all the buttons obtained into an array and put them into the global, and then judge whether to display them through V-if
  • * * 3…. 六四屠杀