位运算在vue权限路由中的应用

RBAC0(基于角色的访问控制)

Role-Based Access Control:使用角色描述用户和权限(operation+resource)之间的关系,用户和权限之间无需直接关联

RBAC 基本模型如图所示(图片来自有赞权限系统):

位运算在vue权限路由中的应用

本质上,角色就是一组权限的集合。

VUE权限路由的实现方案

0x01

后端表结构:

位运算在vue权限路由中的应用

在项目中需要进行权限控制的路由可能是动态变化的。也许领导说某个页面现在不需要权限控制,然后过两天又需要了。。。
所以在后端维护一张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权限路由实现方式总结

链接:

有赞权限系统

vue-element-admin

原文链接:https://juejin.im/post/5d297e4ce51d454f7230259d

发表评论

登录后才能评论