Vue許可權路由實現總結

小阿鑫發表於2021-07-20

前言

   年前完工了做了半年的鐵路後臺管理系統,系統整體業務比較複雜,這也是我到公司從 0 到 1 的 一個完整系統實踐,做這個系統過程中踩了不少坑,也學到了很多。

  做完這個系統沒多久,緊接著又一個系統來了,沒及時總結,慚愧哈!其實我們在做的後臺管理系統大多數基礎框架都一樣,後臺管理系統 主要的 是 角色許可權管理 按鈕許可權管理 選單管理 , 其它的業務主要圍繞在這個基礎之上進行擴充套件,最終 構成了 符合業務的後臺管理系統.

 由於我司的專案都是採用 Vue 技術棧,那麼該文章也是講解 Vue 如何進行許可權管理 進行講解。

結尾有彩蛋哦!

許可權授權登入

任何一個後臺管理系統都是 首先從登入開始,登入後返回使用者基本資訊,以及token。

  • token :存入 sessionStronge / localStronge中,然後加入到 封裝好的 Axios 的 請求頭中,每次請求攜帶token.
  • 使用者基本資訊

登入成功後同時要做很多事情,具體業務具體對待。後臺管理系統 登入成功後會請求當前使用者的選單許可權介面,來獲取使用者的可訪問的路由(動態路由),獲取成功後, Vue Router 是不能直接使用的,必須得解析成符合 Vue Router 可識別的格式 .

登入

    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true;
          login(this.loginForm)
            .then(res => {
              if (res.code === 200) {
                // 存放token
                sessionStorage.setItem("tokens", res.data.token);
                // 觸發Vuex 來 載入 獲取當前使用者的選單,並解析路由
                store.dispatch("setMenuList");
                this.$message({
                  message: "登入成功",
                  type: "success",
                  duration: 1000
                });
                this.$router.replace({ path: "/dashboard" });
              }
            })
            .catch(() => {
              this.loading = false;
            });
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    }

獲取當前使用者選單,解析路由

登入成功後,本文通過 Vuex 來獲取當前使用者選單和解析路由的。

store.dispatch("setMenuList");

/*
 * @Description:
 * @Author: ZhangXin
 * @Date: 2021-02-02 16:10:59
 * @LastEditTime: 2021-02-23 23:03:30
 * @LastEditors: ZhangXin
 */
// getMenu 解析後臺路由
import { getMenu } from '../../utils/getMenu'
// 引入路由 和 靜態路由
import router, { constantRoutes } from '../../router/index'
const state = {
  routerType: '',
  // 選單路由
  meunList: []
}

const mutations = {
  SET_ROUTER_TYPE(state, type) {
    state.routerType = type
  },
  SET_ROUTER_MENULIST(state, list) {
    // 靜態路由 +  動態路由  合併  完整路由
    const array = constantRoutes.concat(list)
    state.meunList = array
    router.options.routes = array
    router.addRoutes([...array])
  }
}

const actions = {
  setMenuList({ commit, state }) {
    // 接收返回來的 路由陣列
    return new Promise((resolve, reject) => {
      getMenu().then(res => {
        commit('SET_ROUTER_TYPE', '')
        commit('SET_ROUTER_MENULIST', res)
        resolve(res)
      })
    })
  }
}
export default {
  state,
  mutations,
  actions
}

解析後端返回來路由(重點)

封裝好的解析後端返回來的路由,這塊主要是為了在 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: 解析後端返回來的選單樹
 * @param {*} data 後端返回來的路由樹
 * @param {*} arr 選單
 * @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,
      // 當時這塊踩坑了
      component: datas.component === 'Layout' ? Layout : resolve => require([`@/views/${datas.component}.vue`], resolve),
      meta: {
        title: datas.meta.title,
        icon: datas.meta.icon,
        // 用來存放按鈕許可權
        button: datas.meta.button
      },
      //  redirect: datas.redirect,
      id: datas.id,
      // 子路由
      children: []
    })

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


/**
 * @description: 獲取當前登入使用者的選單
 * @param {*}
 * @return {*}
 */
export function getMenu() {
  return new Promise(function (resolve, reject) {
    getUserAuthMenu().then(res => {
      if(res.code === 200){
      const datas = res.data
      // 呼叫 tree 來解析後端返回來的樹
      resolve(tree(datas, []))
      }

    })
  })
}

後端接收路由格式

Vue許可權路由實現總結

前端接收到的真實選單樹

Vue許可權路由實現總結

頁面重新整理,路由丟失

到此為止,已經實現了 Vue 動態許可權控制 ,別高興的太早,哈哈,一重新整理頁面,頁面就進入了 404 頁面

這是為什麼呢 ?

因為存入 Vuex 中的資料,一重新整理頁面,就會清空,那麼當然找不到當前路由,就進入 404 頁面了 .

如何處理呢?

**一、 可以 將 靜態和 動態 構成的完整路由 存放在 sessionStronge / localStronge 中,然後頁面重新整理時,通過在 全域性入口檔案 App.vue 的 生命週期 created 中 ,將 router = sessionStronge / localStronge 存入的完整的路由,頁面在重新整理時,它會重新載入完整的路由。 **

二、如果是使用Vuex來獲取和解析使用者選單的話, 那麼你可以在全域性入口檔案 App.vue 的 生命週期 created 中 ,再次執行 Vuex Action 來重新載入使用者選單

我這塊直接在 App.vue 的 生命週期 created 中 , 再次執行了 Vuex 來進行載入和解析,沒有做其它操作。 當然了,具體業務具體對待。

<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() {
      //只要重新整理頁面,就會重新載入路由樹,保證了路由不會丟失資料
      store.dispatch("setMenuList");
  }
};
</script>

總結

核心思想

  • 1.定義符合 當前專案業務路由格式,前後端按這個接收傳遞
  • 2.前端解析後端返回的動態路由,生成Vue Router 可識別格式,最後拼接完整路由
  • 3.重新整理路由丟失處理

按鈕許可權控制

  • 1.當前元件 路由 攜帶可使用的 按鈕許可權,存入陣列中,通過v-if 來判斷是否顯示
  • 2.登入時,單獨獲取整個系統的按鈕許可權,將獲取到的所有按鈕 存入一個陣列中,放入全域性中,然後,通過 v-if 來判斷是否顯示
  • **3. ............ **

公眾號

相關文章