Role-Based Access Control:使用角色描述用戶和權限(operation+resource)之間的關係,用戶和權限之間無需直接關聯前端
RBAC 基本模型如圖所示(圖片來自有贊權限系統):vue
本質上,角色就是一組權限的集合。git
後端表結構:github
在項目中須要進行權限控制的路由多是動態變化的。也許領導說某個頁面如今不須要權限控制,而後過兩天又須要了。。。
因此在後端維護一張route表,每一個路由對應一條記錄,id自增,記錄路由的url,是否啓用等。這樣全部須要權限控制的路由都分配了一個惟一id。後端
上面說到角色的本質是一組權限的集合,那麼能夠用int型的二進制位來表示這個集合,0表示沒有權限,1表示有權限。
在JavaScript中,按位操做符(Bitwise operators)將其操做數(operands)看成32位的比特序列(由0和1組成)。rout表的id與比特序號進行關聯。例如50的二進制表示爲110010
,那麼表示有id爲2,5,6的路由的訪問權限。routes表的裏id值表示控制這條路由權限在二進制位中的序號。async
role_route表中的permissions和offset字段描述了一個角色所擁有的權限,表示爲{(offset1,permissions1),(offset2,permissions2)…(offsetN,permissionsN)}。即用permissions和offset字段關聯routes表的id。例如某個角色在role_route表中有兩條記錄offset爲0,permissions爲1和offset爲1,permissions爲2,那麼這個角色完整的二進制集合爲10(省略30個0)1
,在routes表中所關聯的路由id爲1和33,即這個角色擁有路由id爲1和33的權限。post
在前端判斷一個路由是否有權限:url
const permissionUtils = { getSingleRoutePermission (id) { return 1 << (id % 31) }, getOffset (id) { return Math.floor(id / 31) }, } // 假設當前用戶擁有的角色在role_route表中關聯兩條記錄: offset爲0,permissions爲100和offset爲1,permissions爲50 const permissions = [100, 50] // offset分別爲0,1 permissionUtils.getSingleRoutePermission(routeId) & permissions[permissionUtils.getOffset(routeId)]
給某個角色增長一個權限:spa
let offset = permissionUtils.getOffset(routeId) permissions.splice(offset, 1, permissions[offset] |= permissionUtils.getSingleRoutePermission(routeId))
這裏簡單描述一下vue-element-admin實現權限路由的思路。code
/** * asyncRoutes * the routes that need to be dynamically loaded based on user roles */ const asyncRoutes = [ { path: '/permission', component: Layout, name: 'Permission', meta: { roles: ['admin', 'editor'] } } ] router.addRoutes(asyncRoutes.reduce((permissionRoutes, route) => { user.roles.some(role => route.meta.roles.includes(role)) && permissionRoutes.push(route) return permissionRoutes }, []))
這裏能夠看到某個路由的訪問權限是寫在路由定義裏的,對於自定義角色和角色較多的狀況不太好處理。上面咱們使用角色來存儲路由的訪問權限,實現將路由的定義和權限控制分開。
使用二進制序列來存儲路由權限,對於多角色和自定義角色有很好的支持。
對於用戶自定義角色的狀況,咱們只須要將須要管理的路由id設置到對應的二進制位便可,不影響路由的定義,且能夠無限建立角色。
對於多角色的狀況,只要將用戶的全部角色作|
操做便可,例如 角色1|角色1|···角色N
。
在角色數量和路由數量大的狀況下,使用二進制位方式管理權限應該是不錯的選擇。
這裏並無對路由和菜單是否分離,路由是否由後端返回以及是否使用全局路由守衛等問題進行討論,使用二進制位存儲權限能夠與這幾種方式相結合,具體選擇看業務和我的喜愛。
對於路由和菜單的管理能夠看看這篇文章的總結:vue權限路由實現方式總結
連接: