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权限路由实现方式总结
连接: