RBAC0(基于角色的访问控制)
Role-Based Access Control:使用角色描述用户和权限(operation+resource)之间的关系,用户和权限之间无需直接关联
RBAC 基本模型如图所示(图片来自有赞权限系统):
本质上,角色就是一组权限的集合。
VUE权限路由的实现方案
0x01
后端表结构:
在项目中需要进行权限控制的路由可能是动态变化的。也许领导说某个页面现在不需要权限控制,然后过两天又需要了。。。
所以在后端维护一张route表,每个路由对应一条记录,id自增,记录路由的url,是否启用等。这样所有需要权限控制的路由都分配了一个唯一id。
上面说到角色的本质是一组权限的集合,那么可以用int型的二进制位来表示这个集合,0表示没有权限,1表示有权限。
在JavaScript中,按位操作符(Bitwise operators)将其操作数(operands)当作32位的比特序列(由0和1组成)。rout表的id与比特序号进行关联。例如50的二进制表示为110010
,那么表示有id为2,5,6的路由的访问权限。routes表的里id值表示控制这条路由权限在二进制位中的序号。
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的权限。
0x02
在前端判断一个路由是否有权限:
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)]
给某个角色增加一个权限:
let offset = permissionUtils.getOffset(routeId)
permissions.splice(offset, 1, permissions[offset] |= permissionUtils.getSingleRoutePermission(routeId))
0x03
这里简单描述一下vue-element-admin实现权限路由的思路。
/**
* 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
}, []))
这里可以看到某个路由的访问权限是写在路由定义里的,对于自定义角色和角色较多的情况不太好处理。上面我们使用角色来存储路由的访问权限,实现将路由的定义和权限控制分开。
0x04
使用二进制序列来存储路由权限,对于多角色和自定义角色有很好的支持。
对于用户自定义角色的情况,我们只需要将需要管理的路由id设置到对应的二进制位即可,不影响路由的定义,且可以无限创建角色。
对于多角色的情况,只要将用户的所有角色做|
操作即可,例如 角色1|角色1|···角色N
。
在角色数量和路由数量大的情况下,使用二进制位方式管理权限应该是不错的选择。
0x05
这里并没有对路由和菜单是否分离,路由是否由后端返回以及是否使用全局路由守卫等问题进行讨论,使用二进制位存储权限可以与这几种方式相结合,具体选择看业务和个人喜好。
对于路由和菜单的管理可以看看这篇文章的总结:vue权限路由实现方式总结
链接: