本文主要想對前端許可權管理功能實現做一個分享,所以並不會對後臺管理的框架結構做太詳細介紹,如果有朋友對其他有興趣可以留言。
基本設計和分析
- 前端 vue + elementui
- 服務端: node + mysql + nginx
主要功能
模仿的是思否論壇,開啟思否頁面,根據頁面的功能點,設計出相關的資料表,和管理系統需要的相關頁面。 計劃後臺管理需要完成的功能:
- 許可權管理(選單許可權到資料許可權) -- 已完成
- 工作流 (問答和文章在某個條件內,提交需要走流程)-- 未完成
- socket (對使用者點贊,評論,系統通知等訊息進行實時推送)-- 未完成
- 檔案管理(將頁面需要用到的檔案上傳管理,其他頁面都統一訪問檔案庫資源)-- 已完成
- 基本業務 (業務頁面)-- 部分完成
模組相關介紹
模組 | 功能 | 頁面編碼 | 描述 |
---|---|---|---|
登入 | 登入 | login | 選單中不顯示 |
401 | 401 | 401 | 角色無訪問許可權時進入這個頁面 |
404 | 404 | 404 | 訪問選單不存在時進入這個頁面 |
首頁 | 首頁 | home | |
運維中心 | opsCenter | ||
- | 問答管理 | questionMan | |
- | 專欄管理 | blogMan | |
- | 文章管理 | articleMan | |
- | 講堂管理 | liveMan | |
- | 活動管理 | activityMan | |
- | 廣告位 | advertising | |
工作流 | workflow | ||
- | 流程設計 | processDesign | |
- | 業務管理 | businessMan | |
- | 已辦事項 | finishedItems | |
- | 未辦事項 | unfinishedItems | |
檔案庫 | library | ||
- | 圖片管理 | imgMan | |
- | 檔案管理 | fileMan | |
論壇配置 | bbsConfig | ||
- | 輪播 | carousel | |
- | 技術頻道 | techSquare | |
- | 通知 | notices | |
- | 標籤型別管理 | tagTypeMan | |
- | 標籤管理 | tagMan | |
系統管理 | sysMan | ||
- | 使用者管理 | userMan | |
- | 角色管理 | roleMan | |
- | 選單管理 | menuMan | |
- | 區域管理 | areaMan | |
- | 圖表配置 | chartConfig | |
- | 系統日誌 | log |
程式碼結構
├── admin // 打包產出檔案
├── node_module // npm載入所需的專案依賴模組
├── public // 靜態入口
├── src // 原始碼
│ ├── api // 所有請求
│ ├── assets // 主題 字型 圖片等靜態資源
│ ├── common // 全域性公用配置
│ │ ├── config // 配置全域性路由許可權和錯誤捕獲
│ │ ├── mixin // 一些vue公用的mixin
│ │ ├── js // 編寫公有的方法
│ │ └── style // 編寫公有的樣式
│ ├── components // 全域性公用元件
│ ├── directive // 自定義指令
│ ├── router // 路由
│ ├── store // 全域性 store管理
│ ├── views // view
│ ├── App.vue // 入口頁面
│ └── main.js // 入口 載入元件 初始化等
├── static // 第三方不打包資源
├── .babelrc // babel-loader 配置
├── eslintrc.js // eslint 配置項
├── .gitignore // git 忽略項
├── vue.config.js // vue-cli@3.0+ 配置檔案
└── package.json // package.json
複製程式碼
許可權設計
進入正文,關於許可權設計,圍繞的是前端頁面,但是會將前端和後端的邏輯都講出來。
使用者管理
建立(自上到下,類似html節點一樣父級可以獲取到子集)
前端頁面
看圖中圈起來的地方,前端看到的邏輯是這樣的:
- 當前使用者為admin
- 樹用右鍵操作是admin建立的使用者
- 樹用右鍵操作建立的使用者admin可以管理 就是建立了一個使用者,這個使用者建立的使用者以及建立使用者建立的使用者,都可以被當前建立者管理。
介面邏輯
- 查詢到資料庫中所有的使用者ID
- 通過使用者ID和建立人ID的關係,通過建立樹狀資料,得到當前使用者建立的使用者樹
- 遞迴從使用者樹中得到所有屬於當前使用者子集的使用者ID
- select * from table where id in (子集使用者id) 通過這個邏輯,可以得到所有當前使用者建立的子集,但是第一步有很大的問題,一旦使用者數量巨大,這樣查詢會很慢。母目前只是為了功能實現,暫未考慮到效能方面,如果有好的方法,希望指點。
刪除(根據是否有建立使用者)
前端頁面
- 刪除使用者,呼叫介面判斷使用者是否有子集,存在->3,不存在->2
- 不存在直接刪除
- 存在需要先將當前建立的使用者轉移給其他使用者(其他使用者不可為他的子集)
- 將使用者轉移成功,則此時子集為空 ->2
介面邏輯
- 查詢到資料庫中是否存在建立人ID為當前要刪除的使用者ID
- 存在則無法刪除當前使用者
- 前端呼叫戶轉移介面,將當前使用者建立的使用者轉移給其他人後,此時可刪除該使用者
選單管理
選單設計的時候分為三個型別,管理平臺,論壇,移動端,但是不一定會寫完,感覺一個人寫好累呀~~~~ 通過選單又分還有預設佈局元件和頁面元件的區分,佈局元件為layout,頁面元件則為他的子路由,通過巢狀的形式,組成一個完整的頁面。
頁面
目前頁面上都是通過右鍵點選樹元件,進入操作,如圖所示,可以對選單進行增刪改查操作。選單欄位的定義和相關用處 欄位定義是這樣的: 看到圖中有這些欄位,對主要欄位說明:
- 選單編碼(對應前端頁面的檔名,比如userMan, 渲染時就會找到 */userMan/index去resolve)
- 選單元件 (指的是layout等,後面如果需要做多佈局,通過這個設定頁面即可有不同佈局)
-- ----------------------------
-- bbs_menu
-- ----------------------------
DROP TABLE IF EXISTS `bbs_menu`;
CREATE TABLE `bbs_menu` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`pid` INT(11) DEFAULT '0',
`type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '選單型別: 1. 管理平臺選單 2. BBS選單 3. 移動端選單',
`code` VARCHAR(48) NOT NULL COMMENT '選單編碼',
`name` VARCHAR(48) NOT NULL COMMENT '選單名稱',
`component` tinyint(4) NOT NULL COMMENT '對應元件: -1. 根節點 1. 頁面元件 2.預設佈局 3456...擴充套件布局',
`icon` VARCHAR(128) DEFAULT NULL COMMENT '選單圖示',
`alias` VARCHAR(128) DEFAULT NULL COMMENT '別名',
`redirect` VARCHAR(128) DEFAULT NULL COMMENT '重定向路徑: 配置選單編碼或URL',
`sort` INT(11) NOT NULL,
`desc` VARCHAR(128) DEFAULT NULL,
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '狀態: 0:停用,1:啟用(預設為1)',
`create_user` INT(11) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_user` INT(11) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`delete_user` INT(11) DEFAULT NULL,
`delete_time` datetime DEFAULT NULL,
`flag` tinyint(4) NOT NULL DEFAULT '1' COMMENT '狀態: 0:刪除,1:可用(預設為1)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='選單表';
複製程式碼
id: '', // *唯一ID
pid: '', // *父ID
type: '', // *選單型別
code: '', // *選單編碼
name: '', // *選單名稱
component: '', // *選單元件
icon: '', // 選單圖示
redirect: '', // 重定向路徑
sort: '', // *排序
desc: '', // 描述
status: 1 // *狀態: 0:停用,1:啟用(預設為1)'
複製程式碼
有什麼用處呢和好處呢,就個人而言,就是覺得把路由表放在資料庫,讓專案更易於維護,在頁面中通過一個匹配邏輯,可以將所有欄位組裝成為可以使用的路由表:
// 得到頁面路徑
function getPath (arr, child, code) {
const pItem = arr.find(item => child.pid === item.id)
// 當前元素還存在父節點, 且父節點不為根節點
if (arr.find(item => pItem.pid === item.id && item.pid > -1)) {
getPath(arr, pItem, `${pItem.code}/${code}`)
} else {
return `${pItem.code}/${code}`
}
}
// 對基礎資料的處理
item.meta = {}
item.meta.title = item.name
item.meta.icon = item.icon
item.meta.id = item.id
// 使路由名字具有唯一性
item.name = item.name + index
// 設定對應的頁面路徑
item.path = '/' + item.code
// 設定頁面對應的元件 對應元件: -1. 根節點 1. 頁面元件 2.預設佈局 3456...擴充套件布局
switch (item.component) {
case -1:
console.log('根節點,已經過濾掉了')
break
case 1:
item.component = resolve => require([`@/views/${getPath(menu, item, item.code)}/index`], resolve)
break
case 2:
item.component = Layout
break
default:
item.component = resolve => require(['@/views/errorPage/401'], resolve)
break
}
複製程式碼
通過這種方式,在設定頁面許可權的時候,只需要介面設定當前角色對應的選單,使用者查詢的時候能獲取到的就是當前分配給他的許可權,將這個許可權組裝成路由表,即可。
資料許可權
上面說的是選單的配置,以及生成。然後和每個頁面相關的資料許可權,需要點選到頁面級別的選單才可以訪問到,如圖:
選中一個選單之後,可以對這個選單新增資料許可權的控制,比如大到可以進行新增,編輯,刪除等操作,小到可以對某些資料的顯示隱藏。
資料許可權的實現
主要是欄位設計,所以對圖中欄位(開發人員錄入)詳細說明:
- 功能編碼 (頁面編碼:功能編碼,主要用於前端控制顯隱)
- 功能api (介面編碼,後端通過判斷使用者是否存在這個編碼,來判斷是否存在操作許可權)
- 請求方式 (restfulApi情況下,因為api編碼相同,需要根據請求方式來判斷使用者的操作許可權)
前端實現
分配完許可權之後,前端頁面在對應的按鈕或要操作的dom上,通過v-if 功能編碼是否存在來設定操作許可權的顯示隱藏。 但是前端的顯隱一旦使用者繞過頁面去訪問介面即可,所以資料許可權前端只是操作顯隱,具體實現還在後端。
後端實現
- 做一個資料許可權中間層,使用者訪問時中間層判斷當前訪問的介面使用者是否擁有許可權
- 怎麼判斷,通過前端設定的功能api和請求方式,去表中查詢當前使用者角色是否可訪問
- 可訪問繼續往下走,不能訪問就拒絕了
角色管理
使用者存在了,選單和資料許可權也配置好了,但是需要角色去將他們關聯到一起。
繫結使用者
這裡設定的邏輯是一個使用者只能繫結一個角色。 角色管理頁面,還是右鍵樹元件,可以看到繫結使用者的選項
分配許可權
同樣是右鍵,可以開始對角色進行分配許可權的操作
左邊是頁面的許可權分配,選中頁面之後,右邊會出現資料許可權的分配:
繼承式的分配許可權
- 總共有100個許可權
- a有50個,a給b分配時,只能分配50個
- 假設a給b分配了30個,c為b的下級,d為c的下級
- c此時無許可權,a或b能分配30個給c,但由於c無許可權,a或b分配給d時,分配的列表為空
總結
建立使用者 建立選單 建立角色 使用者繫結角色,角色分配許可權 完成
最後
微信 lyh1333, 如有問題,新增請備註掘金