iview 權限管理的實現

iview-admin2.0自帶的權限管理

iview-admin2.0自帶權限管理,可以通過設置路由的meta對象的參數access來分配權限。
默認的角色是super_admin和admin,現在我們給文檔這個側邊欄項目分配一個隻有user才能查看的權限

  {
    path: '',
    name: 'doc',
    meta: {
      title: '文檔',
      href: 'https://lison16.github.io/iview-admin-doc/#/',
      icon: 'ios-book',
      access: ['user']
    }
  },

側邊欄就不會顯示文檔這個欄目瞭。在src/store/module/app.js中獲取menuList,這個就是側邊欄的list

  getters: {
    menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access),
    errorCount: state => state.errorList.length
  },

這個getter方法主要是執行瞭getMenuByRouter,接著查看src/libs/util.js找到具體代碼

/**
 * @param {Array} list 通過路由列表得到菜單列表
 * @returns {Array}
 */
export const getMenuByRouter = (list, access) => {
  let res = []
  forEach(list, item => {
    if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
      let obj = {
        icon: (item.meta && item.meta.icon) || '',
        name: item.name,
        meta: item.meta
      }
      if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) {
        obj.children = getMenuByRouter(item.children, access)
      }
      if (item.meta && item.meta.href) obj.href = item.meta.href
      if (showThisMenuEle(item, access)) res.push(obj)
    }
  })
  return res
}
const showThisMenuEle = (item, access) => {
  if (item.meta && item.meta.access && item.meta.access.length) {
    if (hasOneOf(item.meta.access, access)) return true
    else return false
  } else return true
}

到這裡,access判斷權限的過程就比較明白瞭。代碼會獲取state裡存放的用戶信息,主要是access,然後和路由允許的access進行比對,如果用戶的access在路由access列表允許的范圍內就確權,例如用戶access的[‘admin’,’super_admin’],但是我們把文檔的access設置為[‘user’],

hasOneOf(['admin','super_admin'],['user']) // false,鑒權失敗

hasOneOf是iview-admin的工具方法。用於判斷要查詢的數組是否至少有一個元素包含在目標數組中,詳細代碼放在底部。

根據權限控制組件展示

一般我們還需要根據權限去控制頁面元素的展示,比如按鈕。有兩種方法,一種是自定義auth指令,或者自定義一個鑒權組件用來包裹需要鑒權的元素。

自定義auth指令

iview-admin把自定義指令統一放在src/directive文件夾下,directives.js文件負責引入單獨定義在各個文件的自定義指令,統一導出。我們實現一個auth指令:

import draggable from './module/draggable'
import clipboard from './module/clipboard'
import auth from './module/auth'
const directives = {
  draggable,
  clipboard,
  auth
}
export default directives

然後在src/directive/index.js中導出瞭一個importDirective方法,入參是Vue,邏輯是註冊指令。

import directive from './directives'

const importDirective = Vue => {
  /**
   * 拖拽指令 v-draggable="options"
   * options = {
   *  trigger: /這裡傳入作為拖拽觸發器的CSS選擇器/,
   *  body:    /這裡傳入需要移動容器的CSS選擇器/,
   *  recover: /拖動結束之後是否恢復到原來的位置/
   * }
   */
  Vue.directive('draggable', directive.draggable)
  /**
   * clipboard指令 v-draggable="options"
   * options = {
   *  value:    /在輸入框中使用v-model綁定的值/,
   *  success:  /復制成功後的回調/,
   *  error:    /復制失敗後的回調/
   * }
   */
  Vue.directive('clipboard', directive.clipboard)
  Vue.directive('auth', directive.auth) 
}

export default importDirective

這個importDirective方法在main.js裡面被用到瞭,並且把真實的Vue傳入做為入參。

import importDirective from '@/directive'
/**
 * 註冊指令
 */
importDirective(Vue)
...

編輯src/directive/module/auth.js

import store from '@/store'
export default {
  inserted: (el, binding, vnode) => {
    const value = binding.value
    const access = store.state.user.access
    if (access.indexOf(value) === -1) {
      el.remove()
    }
  }
}

我們新增一個auth指令,並導出。在註入的時候進行權限判斷,如果確權成功就不做什麼,如果失敗就把元素刪除。
使用試試,拿頂部的折疊菜單按鈕做例子,beader-bar.vue

<template>
  <div class="header-bar">
    <sider-trigger v-auth="'admin'" :collapsed="collapsed" icon="md-menu" @on-change="handleCollpasedChange"></sider-trigger>
    ...
  </div>
</template>

當v-auth=”‘admin'”的時候顯示按鈕,如果是user則會隱藏按鈕。

自定義auth組件

也可以通過自定義auth組件的方式來實現,創建一個函數式組件auth.vue

<script>
import store from '@/store'
export default {
  functional: true,
  props: {
    authority: {
      type: String,
      require: true
    }
  },
  render (h, context) {
    const { props, scopedSlots } = context
    const access = store.state.user.access
    return access.indexOf(props.authority) > -1 ? scopedSlots.default() : null
  }
}
</script>

如果確權成功就返回slot,否則返回null,這樣被auth包裹的元素就不會展現瞭。然後把auth.vue註冊為全局組件,免得每次使用都要import一下。編輯main.js

import Auth from '_c/auth/auth.vue'
// 註冊組件
Vue.component('Auth',Auth)

使用的時候直接用auth包裹組件即可

<template>
  <div class="header-bar">
    <Auth authority="user">
      <sider-trigger :collapsed="collapsed" icon="md-menu" @on-change="handleCollpasedChange"></sider-trigger>
    </Auth>
  </div>
</template>

總結

不論是用組件式的寫法還是自定義指令都能實現,組件的方式實現要寫的代碼多一點,用自定義指令比較靈活,此外有一點不同,自定義指令如果確權失敗,是把元素直接刪除掉瞭,所以此時如果再由admin改為user,元素還是不會展示的,因為已經被刪除瞭嘛,需要刷新一下頁面才能顯示出來,但是如果是組件式的就不會,能夠靈活響應。這個一般影響不大。

註意到我把access設置為瞭一個String,如果設置為一個數組也可以,iview自帶的hasOneOf方法可以很好的使用

/**
 * @param {Array} target 目標數組
 * @param {Array} arr 需要查詢的數組
 * @description 判斷要查詢的數組是否至少有一個元素包含在目標數組中
 */
export const hasOneOf = (targetarr, arr) => {
  return targetarr.some(_ => arr.indexOf(_) > -1)
}

到此這篇關於iview 權限管理的實現的文章就介紹到這瞭,更多相關iview 權限管理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: