vue專案實踐-前後端分離關於許可權的思路

易墨發表於2018-07-29

前後端分離後許可權的思路

最近看到許多關於許可權的思路,但好像都是使用動態載入路由的方式,現在也分享下我在專案中使用的解決方案。
前後端分離關於許可權的處理每個人都不一樣,根據專案選擇制定合適的方案就好

我的方案是:

  • 前端掛載所有路由
  • 通過 Api 介面獲取使用者許可權標識(路由名稱)
  • 在路由切換的時候進行許可權校驗
  • 至於頁面的許可權按鈕則通過指令+自定義元件的形式封裝成通用許可權按鈕,通過傳入相應的標識判斷是否現實按鈕
  • 大體流程如下圖所示
    前端許可權處理流程

前後端分離許可權的實現

  1. 路由中定義是否需要驗證許可權:meta:{ auth :true }

路由定義

若是後端專案,一般會包含公用的頭部,側邊導航等公用的部分,這些部分可以將其抽象成一個個元件,建立佈局頁使其更簡單的使用關於路由的引用,在大的專案中發現不適用懶載入能夠更快的熱更新,所以可以根據環境採取不同的載入方式一個簡單的路由

路由結構圖

路由結構

  • _import.[env].js:

生產環境( production )/ testing 的定義 module.exports = file => () => import('@/views/' + file + '.vue') 開發環境( development )的定義 module.exports = file => require('@/views/' + file + '.vue').default 路由匯入程式碼

  • index.js : 使用 vue-router 掛載路由
import Vue from 'vue'
import Router from 'vue-router'
import { routes } from './routes'
import logic from './logic'
Vue.use(Router)

const router = new Router({
  //   mode: 'history',
  routes
})
router.beforeEach(logic.beforeEach)
router.afterEach(logic.afterEach)

export default router
複製程式碼
  • logic.js : 路由鉤子的實現
import { getInfo } from '@/api/modules/account'
const beforeEach = (to, from, next) => {
  if (!to.meta.auth) {
    return next()
  }
  if (!localStorage.token) {
    return next('/login')
  }
  if (window.info) return next()
  getInfo().then(res => {
    localStorage.token = res.data.info.token
    window.info = res.data.info
    window.menus = res.data.menus
    window.modules = res.data.modules
    next()
  })
}
const afterEach = (to, from) => {}

export default {
  beforeEach,
  afterEach
}
複製程式碼
  • routes.js:路由的模組定義
const _import = require('./_import_' + process.env.NODE_ENV)

export const appRouter = [
  {
    path: '/',
    component: Layout,
    children: [
      {
        path: '',
        name: 'home',
        component: _import('dashboard/index'),
        meta: { defAuth: true, auth: true }
      }
    ]
  }
]
export const routes = [...appRouter]
複製程式碼

介面定義

  • account/login 登入成功返回 token,儲存到本地跳轉頁面
  • auth/info 校驗是否有 token 資訊及登入資訊,無則傳送請求獲取登入資訊,選單及許可權模組標識列表

選單載入

新建 Layout 資料夾,將各部分元件再拆成小元件進行拼接後臺元件,樣式使用聖盃佈局,然後稍加改動就能夠實現基本的後臺管理頁佈局 Layout 結構圖

layout

選單結構:

"menus": [
      {
        "menuName": "控制檯",
        "menuIcon": null,
        "menuCode": "home",
        "menuUrl": null
      },
      {
        "menuName": "系統管理",
        "menuIcon": null,
        "children": [
          {
            "menuName": "管理員管理",
            "menuIcon": null,
            "children": [
              {
                "menuName": "管理員列表",
                "menuIcon": null,
                "menuCode": "system-admin-list",
                "menuUrl": null
              }
            ]
          },
          {
            "menuName": "角色列表",
            "menuIcon": null,
            "menuCode": "system-role-list",
            "menuUrl": null
          }
        ]
      }
    ],
複製程式碼

遞迴生成選單元件

<template>
    <dl>
        <template v-for="(item,index) in menus">
            <dt :key="item.menuName">
                <a href="javascript:;" v-if="item.menuUrl" @click="$ui.redirect(item.menuUrl)">{{item.menuName}}</a>
                <router-link :to="{name:item.menuCode}" v-else-if="item.menuCode">{{item.menuName}}</router-link>
                <span v-else>{{item.menuName}}</span>
            </dt>
            <dd class="child-menu" :key="'c_'+index" v-if="item.children&&item.children.length>0">
                <v-app-nav :menus="item.children" />
            </dd>
        </template>
    </dl>
</template>

<script>
export default {
  name: 'v-app-nav',
  props: ['menus']
}
</script>

<style>
</style>
複製程式碼

指令封裝

可以通過指令傳入需要的許可權標識值,進行對按鈕許可權的控制,根據需要控制顯示/啟用

定義

export default {
  auth: {
    inserted: (el, binding) => {
      if (window.modules.indexOf(binding.value) === -1) {
        // el.remove()
        el.setAttribute('disabled', 'disabled')
      }
    }
  }
}
複製程式碼

使用

對於常用的一些按鈕,應封裝到元件中,統一管理風格,也能使起更易維護

<button v-auth="'role_create_create'">新增</button>
複製程式碼

相關連結

文中的實現可以在下面倉庫中找到,不清楚的地方也可以直接檢視原始碼

相關文章