管理系統之許可權的設計和實現

lyh1333發表於2019-06-27

本文主要想對前端許可權管理功能實現做一個分享,所以並不會對後臺管理的框架結構做太詳細介紹,如果有朋友對其他有興趣可以留言。

基本設計和分析

  • 前端 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節點一樣父級可以獲取到子集)

clipboard.png

前端頁面

看圖中圈起來的地方,前端看到的邏輯是這樣的:

  • 當前使用者為admin
  • 樹用右鍵操作admin建立的使用者
  • 樹用右鍵操作建立的使用者admin可以管理 就是建立了一個使用者,這個使用者建立的使用者以及建立使用者建立的使用者,都可以被當前建立者管理。
介面邏輯
  • 查詢到資料庫中所有的使用者ID
  • 通過使用者ID和建立人ID的關係,通過建立樹狀資料,得到當前使用者建立的使用者樹
  • 遞迴從使用者樹中得到所有屬於當前使用者子集的使用者ID
  • select * from table where id in (子集使用者id) 通過這個邏輯,可以得到所有當前使用者建立的子集,但是第一步有很大的問題,一旦使用者數量巨大,這樣查詢會很慢。母目前只是為了功能實現,暫未考慮到效能方面,如果有好的方法,希望指點。

刪除(根據是否有建立使用者)

clipboard.png

clipboard.png

前端頁面
  1. 刪除使用者,呼叫介面判斷使用者是否有子集,存在->3,不存在->2
  2. 不存在直接刪除
  3. 存在需要先將當前建立的使用者轉移給其他使用者(其他使用者不可為他的子集)
  4. 將使用者轉移成功,則此時子集為空 ->2
介面邏輯
  1. 查詢到資料庫中是否存在建立人ID為當前要刪除的使用者ID
  2. 存在則無法刪除當前使用者
  3. 前端呼叫戶轉移介面,將當前使用者建立的使用者轉移給其他人後,此時可刪除該使用者

選單管理

選單設計的時候分為三個型別,管理平臺,論壇,移動端,但是不一定會寫完,感覺一個人寫好累呀~~~~ 通過選單又分還有預設佈局元件和頁面元件的區分,佈局元件為layout,頁面元件則為他的子路由,通過巢狀的形式,組成一個完整的頁面。

clipboard.png

頁面

clipboard.png
目前頁面上都是通過右鍵點選樹元件,進入操作,如圖所示,可以對選單進行增刪改查操作。

選單欄位的定義和相關用處 欄位定義是這樣的: 看到圖中有這些欄位,對主要欄位說明:

  • 選單編碼(對應前端頁面的檔名,比如userMan, 渲染時就會找到 */userMan/index去resolve)
  • 選單元件 (指的是layout等,後面如果需要做多佈局,通過這個設定頁面即可有不同佈局)

clipboard.png

-- ----------------------------
-- 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
              }
複製程式碼

通過這種方式,在設定頁面許可權的時候,只需要介面設定當前角色對應的選單,使用者查詢的時候能獲取到的就是當前分配給他的許可權,將這個許可權組裝成路由表,即可。

資料許可權

上面說的是選單的配置,以及生成。然後和每個頁面相關的資料許可權,需要點選到頁面級別的選單才可以訪問到,如圖:

clipboard.png

選中一個選單之後,可以對這個選單新增資料許可權的控制,比如大到可以進行新增,編輯,刪除等操作,小到可以對某些資料的顯示隱藏。

資料許可權的實現

主要是欄位設計,所以對圖中欄位(開發人員錄入)詳細說明:

  • 功能編碼 (頁面編碼:功能編碼,主要用於前端控制顯隱)
  • 功能api (介面編碼,後端通過判斷使用者是否存在這個編碼,來判斷是否存在操作許可權)
  • 請求方式 (restfulApi情況下,因為api編碼相同,需要根據請求方式來判斷使用者的操作許可權)

clipboard.png

前端實現

分配完許可權之後,前端頁面在對應的按鈕或要操作的dom上,通過v-if 功能編碼是否存在來設定操作許可權的顯示隱藏。 但是前端的顯隱一旦使用者繞過頁面去訪問介面即可,所以資料許可權前端只是操作顯隱,具體實現還在後端。

後端實現
  • 做一個資料許可權中間層,使用者訪問時中間層判斷當前訪問的介面使用者是否擁有許可權
  • 怎麼判斷,通過前端設定的功能api和請求方式,去表中查詢當前使用者角色是否可訪問
  • 可訪問繼續往下走,不能訪問就拒絕了

角色管理

使用者存在了,選單和資料許可權也配置好了,但是需要角色去將他們關聯到一起。

繫結使用者

這裡設定的邏輯是一個使用者只能繫結一個角色。 角色管理頁面,還是右鍵樹元件,可以看到繫結使用者的選項

clipboard.png

clipboard.png

分配許可權

同樣是右鍵,可以開始對角色進行分配許可權的操作

clipboard.png

左邊是頁面的許可權分配,選中頁面之後,右邊會出現資料許可權的分配:

clipboard.png

繼承式的分配許可權
  • 總共有100個許可權
  • a有50個,a給b分配時,只能分配50個
  • 假設a給b分配了30個,c為b的下級,d為c的下級
  • c此時無許可權,a或b能分配30個給c,但由於c無許可權,a或b分配給d時,分配的列表為空

總結

建立使用者 建立選單 建立角色 使用者繫結角色,角色分配許可權 完成

最後

微信 lyh1333, 如有問題,新增請備註掘金

案例地址

node服務

相關文章