国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

如何優雅地在vue中添加權限控制示例詳解

來源:懂視網 責編:小采 時間:2020-11-27 22:00:21
文檔

如何優雅地在vue中添加權限控制示例詳解

如何優雅地在vue中添加權限控制示例詳解:前言 在一個項目中,一些功能會涉及到重要的數據管理,為了確保數據的安全,我們會在項目中加入權限來限制每個用戶的操作。作為前端,我們要做的是配合后端給到的權限數據,做頁面上的各種各樣的限制。 需求 因為這是一個工作上的業務需求,所以對于我來說
推薦度:
導讀如何優雅地在vue中添加權限控制示例詳解:前言 在一個項目中,一些功能會涉及到重要的數據管理,為了確保數據的安全,我們會在項目中加入權限來限制每個用戶的操作。作為前端,我們要做的是配合后端給到的權限數據,做頁面上的各種各樣的限制。 需求 因為這是一個工作上的業務需求,所以對于我來說

前言

在一個項目中,一些功能會涉及到重要的數據管理,為了確保數據的安全,我們會在項目中加入權限來限制每個用戶的操作。作為前端,我們要做的是配合后端給到的權限數據,做頁面上的各種各樣的限制。

需求

因為這是一個工作上的業務需求,所以對于我來說主要有兩個地方需要進行權限控制。

第一個是側邊菜單欄,需要控制顯示與隱藏。

第二個就是頁面內的各個按鈕,彈窗等。

流程

1、如何獲取用戶權限?

后端(當前用戶擁有的權限列表)-> 前端(通過后端的接口獲取到,下文中我們把當前用戶的權限列表叫做 permissionList)

2、前端如何做限制?

通過產品的需求,在項目中進行權限點的配置,然后通過 permissionList 尋找是否有配置的權限點,有就顯示,沒有就不顯示。

3、然后呢?

沒了。

當我剛開始接到這個需求的時候就是這么想的,這有什么難的,不就獲取 permissionList 然后判斷就可以了嘛。后來我才發現真正的需求遠比我想象的復雜。

真正的問題

上面的需求有提到我們主要解決兩個問題,側邊菜單欄的顯示 & 頁面內操作。

假設我們有這樣一個路由的設置(以下只是一個例子):

import VueRouter from 'vue-router'
/* 注意:以下配置僅為部分配置,并且省去了 component 的配置 */
export const routes = [
 {
 path: '/',
 name: 'Admin',
 label: '首頁'
 },
 {
 path: '/user',
 name: 'User',
 label: '用戶',
 redirect: { name: 'UserList' },
 children: [
 {
 path: 'list',
 name: 'UserList',
 label: '用戶列表'
 },
 {
 path: 'group',
 name: 'UserGroup',
 label: '用戶組',
 redirect: { name: 'UserGroupList' },
 children: [
 {
 path: 'list',
 name: 'UserGroupList',
 label: '用戶組列表'
 },
 {
 path: 'config',
 name: 'UserGroupConfig',
 label: '用戶組設置'
 }
 ]
 }
 ]
 },
 {
 path: '/setting',
 name: 'Setting',
 label: '系統設置'
 },
 {
 path: '/login',
 name: 'Login',
 label: '登錄'
 }
]

const router = new VueRouter({
 routes
})

export default router

其中前兩級路由會顯示在側邊欄中,第三級就不會顯示在側邊欄中了。

頁面內操作的權限設置不需要考慮很多其他東西,我們主要針對側邊欄以及路由進行問題的分析,通過分析,主要有以下幾個問題:

  1. 什么時候獲取 permissionList,如何存儲 permissionList
  2. 子路由全都沒權限時不應該顯示本身(例:當用戶列表和用戶組都沒有權限時,用戶也不應該顯示在側邊欄)
  3. 默認重定向的路由沒有權限時,應尋找 children 中有權限的一項重定向(例:用戶路由重定向到用戶列表路由,若用戶列表沒有權限,則應該重定向到用戶組路由)
  4. 當用戶直接輸入沒有權限的 url 時需要跳轉到沒有權限的頁面或其他操作。(路由限制)

下面我們針對以上問題一個一個解決。

什么時候獲取權限,存儲在哪 & 路由限制

我這里是在 router 的 beforeEach 中獲取的,獲取的 permissionList 是存放在 vuex 中。

原因是考慮到要做路由的限制,以及方便后面項目中對權限列表的使用,以下是實現的示例:

首先我們加入權限配置到 router 上:

// 以下只展示部分配置
{
 path: '/user',
 name: 'User',
 label: '用戶',
 meta: {
 permissions: ['U_1']
 },
 redirect: { name: 'UserList' },
 children: [
 {
 path: 'list',
 name: 'UserList',
 label: '用戶列表',
 meta: {
 permissions: ['U_1_1']
 }
 },
 {
 path: 'group',
 name: 'UserGroup',
 label: '用戶組',
 meta: {
 permissions: ['U_1_2']
 },
 redirect: { name: 'UserGroupList' },
 children: [
 {
 path: 'list',
 name: 'UserGroupList',
 label: '用戶組列表',
 meta: {
 permissions: ['U_1_2_1']
 }
 },
 {
 path: 'config',
 name: 'UserGroupConfig',
 label: '用戶組設置',
 meta: {
 permissions: ['U_1_2_2']
 }
 }
 ]
 }
 ]
}

可以看到我們把權限加在了 meta 上,是為了更簡單的從 router.beforeEch 中進行權限判斷,權限設置為一個數組,是因為一個頁面可能涉及多個權限。

接下來我們設置 router.beforeEach :

// 引入項目的 vuex
import store from '@/store'
// 引入判斷是否擁有權限的函數
import { includePermission } from '@/utils/permission'

router.beforeEach(async (to, from, next) => {
 // 先判斷是否為登錄,登錄了才能獲取到權限,怎么判斷登錄就不寫了
 if (!isLogin) {
 try {
 // 這里獲取 permissionList
 await store.dispatch('getPermissionList')
 // 這里判斷當前頁面是否有權限
 const { permissions } = to.meta
 if (permissions) {
 const hasPermission = includePermission(permissions)
 if (!hasPermission) next({ name: 'NoPermission' })
 }
 next()
 }
 } else {
 next({ name: 'Login' })
 }
})

我們可以看到我們需要一個判斷權限的方法 & vuex 中的 getPermissionList 如下:

// @/store
export default {
 state: {
 permissionList: []
 },
 mutations: {
 updatePermissionList: (state, payload) => {
 state.permissionList = payload
 }
 },
 actions: {
 getPermissionList: async ({ state, commit }) => {
 // 這里是為了防止重復獲取
 if (state.permissionList.length) return
 // 發送請求方法省略
 const list = await api.getPermissionList()
 commit('updatePermissionList', list)
 }
 }
}
// @/utils/permission
import store from '@/store'

/**
 * 判斷是否擁有權限
 * @param {Array<string>} permissions - 要判斷的權限列表
 */
function includePermission (permissions = []) {
 // 這里要判斷的權限沒有設置的話,就等于不需要權限,直接返回 true
 if (!permissions.length) return true
 const permissionList = store.state.permissionList
 return !!permissions.find(permission => permissionList.includes(permission))
}

重定向問題

以上我們解決了路由的基本配置與權限如何獲取,怎么限制路由跳轉,接下來我們要處理的就是重定向問題了。
這一點可能和我們項目本身架構有關,我們項目的側邊欄下還有子級,是以下圖中的 tab 切換展現的,正常情況當點擊藥品管理后頁面會重定向到入庫管理的 tab 切換頁面,但當入庫管理沒有權限時,則應該直接重定向到出庫管理界面。

所以想實現以上的效果,我需要重寫 router 的 redirect,做到可以動態判斷(因為在我配置路由時并不知道當前用戶的權限列表)

然后我查看了 vue-router 的文檔,發現了 redirect 可以是一個方法,這樣就可以解決重定向問題了。

vue-router 中 redirect 說明 ,根據說明我們可以改寫 redirect 如下:

// 我們需要引入判斷權限方法
import { includePermission } from '@/utils/permission'

const children = [
 {
 path: 'list',
 name: 'UserList',
 label: '用戶列表',
 meta: {
 permissions: ['U_1_1']
 }
 },
 {
 path: 'group',
 name: 'UserGroup',
 label: '用戶組',
 meta: {
 permissions: ['U_1_2']
 }
 }
]

const routeDemo = {
 path: '/user',
 name: 'User',
 label: '用戶',
 redirect: (to) => {
 if (includePermission(children[0].meta.permissions)) return { name: children[0].name }
 if (includePermission(children[1].meta.permissions)) return { name: children[1].name }
 },
 children
}

雖然問題解決了,但是發現這樣寫下去很麻煩,還要修改 router 的配置,所以我們使用一個方法生成:

// @/utils/permission
/**
 * 創建重定向函數
 * @param {Object} redirect - 重定向對象
 * @param {string} redirect.name - 重定向的組件名稱
 * @param {Array<any>} children - 子列表
 */
function createRedirectFn (redirect = {}, children = []) {
 // 避免緩存太大,只保留 children 的 name 和 permissions
 const permissionChildren = children.map(({ name = '', meta: { permissions = [] } = {} }) => ({ name, permissions }))
 return function (to) {
 // 這里一定不能在 return 的函數外面篩選,因為權限是異步獲取的
 const hasPermissionChildren = permissionChildren.filter(item => includePermission(item.permissions))
 // 默認填寫的重定向的 name
 const defaultName = redirect.name || ''
 // 如果默認重定向沒有權限,則從 children 中選擇第一個有權限的路由做重定向
 const firstPermissionName = (hasPermissionChildren[0] || { name: '' }).name
 // 判斷是否需要修改默認的重定向
 const saveDefaultName = !!hasPermissionChildren.find(item => item.name === defaultName && defaultName)
 if (saveDefaultName) return { name: defaultName }
 else return firstPermissionName ? { name: firstPermissionName } : redirect
 }
}

然后我們就可以改寫為:

// 我們需要引入判斷權限方法
import { includePermission, createRedirectFn } from '@/utils/permission'

const children = [
 {
 path: 'list',
 name: 'UserList',
 label: '用戶列表',
 meta: {
 permissions: ['U_1_1']
 }
 },
 {
 path: 'group',
 name: 'UserGroup',
 label: '用戶組',
 meta: {
 permissions: ['U_1_2']
 }
 }
]

const routeDemo = {
 path: '/user',
 name: 'User',
 label: '用戶',
 redirect: createRedirectFn({ name: 'UserList' }, children),
 children
}

這樣稍微簡潔一些,但我還是需要一個一個路由去修改,所以我又寫了一個方法來遞歸 router 配置,并重寫他們的 redirect:

// @/utils/permission
/**
 * 創建有權限的路由配置(多級)
 * @param {Object} config - 路由配置對象
 * @param {Object} config.redirect - 必須是 children 中的一個,并且使用 name
 */
function createPermissionRouter ({ redirect, children = [], ...others }) {
 const needRecursion = !!children.length
 if (needRecursion) {
 return {
 ...others,
 redirect: createRedirectFn(redirect, children),
 children: children.map(item => createPermissionRouter(item))
 }
 } else {
 return {
 ...others,
 redirect
 }
 }
}

這樣我們只需要在最外層的 router 配置加上這樣一層函數就可以了:

import { createPermissionRouter } from '@/utils/permission'

const routesConfig = [
 {
 path: '/user',
 name: 'User',
 label: '用戶',
 meta: {
 permissions: ['U_1']
 },
 redirect: { name: 'UserList' },
 children: [
 {
 path: 'list',
 name: 'UserList',
 label: '用戶列表',
 meta: {
 permissions: ['U_1_1']
 }
 },
 {
 path: 'group',
 name: 'UserGroup',
 label: '用戶組',
 meta: {
 permissions: ['U_1_2']
 },
 redirect: { name: 'UserGroupList' },
 children: [
 {
 path: 'list',
 name: 'UserGroupList',
 label: '用戶組列表',
 meta: {
 permissions: ['U_1_2_1']
 }
 },
 {
 path: 'config',
 name: 'UserGroupConfig',
 label: '用戶組設置',
 meta: {
 permissions: ['U_1_2_2']
 }
 }
 ]
 }
 ]
 }
]

export const routes = routesConfig.map(item => createPermissionRouter(item))

const router = new VueRouter({
 routes
})

export default router

當然這樣寫還有一個好處,其實你并不需要設置 redirect,這樣會自動重定向到 children 的第一個有權限的路由

側邊欄顯示問題

我們的項目使用的是根據路由的配置來生成側邊欄的,當然會加一些其他的參數來顯示顯示層級等問題,這里就不寫具體代碼了,如何解決側邊欄 children 全都無權限不顯示的問題呢。

這里我的思路是,把路由的配置也一同更新到 vuex 中,然后側邊欄配置從 vuex 中的配置來讀取。

由于這個地方涉及修改的東西有點多,而且涉及業務,我就不把代碼拿出來了,你可以自行實驗。

方便團隊部署權限點的方法

以上我們解決了大部分權限的問題,那么還有很多涉及到業務邏輯的權限點的部署,所以為了團隊中其他人可以優雅簡單的部署權限點到各個頁面中,我在項目中提供了以下幾種方式來部署權限:

通過指令 v-permission 來直接在 template 上設置

<div v-permission="['U_1']"></div>

通過全局方法 this.$permission 判斷,因為有些權限并非在模版中的

{
 hasPermission () {
 // 通過方法 $permission 判斷是否擁有權限
 return this.$permission(['U_1_1', 'U_1_2'])
 }
}

這里要注意,為了 $permission 方法的返回值是可被監測的,判斷時需要從 this.$store 中來判斷,以下為實現代碼:

// @/utils/permission
/**
 * 判斷是否擁有權限
 * @param {Array<string|number>} permissions - 要判斷的權限列表
 * @param {Object} permissionList - 傳入 store 中的權限列表以實現數據可監測
 */
function includePermissionWithStore (permissions = [], permissionList = []) {
 if (!permissions.length) return true
 return !!permissions.find(permission => permissionList.includes(permission))
}
import { includePermissionWithStore } from '@/utils/permission'
export default {
 install (Vue, options) {
 Vue.prototype.$permission = function (permissions) {
 const permissionList = this.$store.state.permissionList
 return includePermissionWithStore(permissions, permissionList)
 }
 }
}

以下為指令的實現代碼(為了不與 v-if 沖突,這里控制顯示隱藏通過添加/移除 className 的方式):

// @/directive/permission
import { includePermission } from '@/utils/permission'
const permissionHandle = (el, binding) => {
 const permissions = binding.value
 if (!includePermission(permissions)) {
 el.classList.add('hide')
 } else {
 el.classList.remove('hide')
 }
}
export default {
 inserted: permissionHandle,
 update: permissionHandle
}

總結

針對之前的問題,有以下的總結:

1、什么時候獲取 permissionList,如何存儲 permissionList

router.beforeEach 獲取,存儲在 vuex。

2、子路由全都沒權限時不應該顯示本身(例:當用戶列表和用戶設置都沒有權限時,用戶也不應該顯示在側邊欄)

通過存儲路由配置到 vuex 中,生成側邊欄設置,獲取權限后修改 vuex 中的配置控制顯示 & 隱藏。

3、默認重定向的路由沒有權限時,應尋找 children 中有權限的一項重定向(例:用戶路由重定向到用戶列表路由,若用戶列表沒有權限,則應該重定向到用戶組路由)

通過 vue-router 中 redirect 設置為 Function 來實現

4、當用戶直接輸入沒有權限的 url 時需要跳轉到沒有權限的頁面或其他操作。(路由限制)

在 meta 中設置權限, router.beforeEach 中判斷權限。

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

如何優雅地在vue中添加權限控制示例詳解

如何優雅地在vue中添加權限控制示例詳解:前言 在一個項目中,一些功能會涉及到重要的數據管理,為了確保數據的安全,我們會在項目中加入權限來限制每個用戶的操作。作為前端,我們要做的是配合后端給到的權限數據,做頁面上的各種各樣的限制。 需求 因為這是一個工作上的業務需求,所以對于我來說
推薦度:
標簽: 如何在 VUE 權限
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 最新国产精品视频免费看 | 亚洲欧美国产精品 | 在线观看视频日韩 | 国产第10页 | 国产高清在线免费视频 | 欧美日韩网站 | 亚洲一区二区三区成人 | 欧美综合图区亚洲综合图区 | 国产精品三级在线观看 | 欧美激情一区二区 | 欧美日韩伦理 | 欧美综合视频 | er久99久热只有精品国产 | 国产特级全黄一级毛片不卡 | 成人毛片免费免费 | 欧美一区二区三区视频在线观看 | 在线免费观看国产精品 | 欧美日本一道本 | 国产免费资源高清小视频在线观看 | 久久久影院亚洲精品 | 亚洲午夜视频 | 黄毛片| 黄网站色视频免费观看45分钟 | 亚洲欧美精品成人久久91 | er久99久热只有精品国产 | 日韩二三区 | 亚洲欧美在线免费观看 | 在线观看亚洲欧美 | 欧美精品一区二区三区在线播放 | 国内精品在线播放 | 在线另类 | 一区二区三区在线免费视频 | 国产精品九九 | 亚洲国产精品热久久 | 五十路中文字幕 | 91区国产| 欧美日韩国产在线人 | 亚洲欧洲综合在线 | 五月天婷婷基地 | 日韩一区三区 | 亚洲首页在线观看 |