一,简单的权限模型
有个访问权限列表如下:
用户1 --> 查看文件 用户1 --> 编辑文件 用户2 --> 查看文件 用户2 --> 编辑文件 ...
每个用户的每个权限,都保存在该表中,这种直接将权限绑定在用户上的方式就叫做基于用户的权限管理,ACL(Access Control List)。
ACL的优点是简单易用、易于理解。缺点是系统逐渐复杂以后,用户和权限直接挂钩,授予权限时比较分散、不能集中管理,增加了复杂性。
这时,人们就设计了基于角色的访问控制 RBAC(Role Based Access Control)。
二,RBAC 基于角色的访问控制
通过角色关联用户,角色关联权限的方式间接赋予用户权限。相对于 ACL 多了“角色”,只要为某个角色设置好权限,只需调整用户关联的角色权限,即可批量的用户权限调整。
用户和角色是多对一关系,用户和角色是多对多关系。通常,多对多更符合现实世界。比如,一些公司,HR 也兼职行政。
上面这种 RBAC 有时也被称为 RBAC0,在 RBAC0 的基础上,还产生了 RBAC1、RBAC2 和 RBAC3。RBAC1模型,增加了子角色,引入了继承概念,即子角色可以继承父角色的所有权限。RBAC2模型增加了对角色的一些限制:角色互斥、基数约束、先决条件角色等。RBAC3模型包含了RBAC1和RBAC2。
一般情况先使用,使用 RBAC0 模型就可以满足常规的权限管理系统设计。
三,一个简单的 RBAC 实现
/** * RBAC * * 用户角色关系存储在 tb_user_meta, meta_key='role', meta_value 名字 */ import dbUtil from './db.util.mjs'; const rbac = { roles: ['superadmin', 'admin', 'user', 'guest'], permissions: [ { permission: 'admin.user.show', title: '查看用户' }, { permission: 'admin.user.store', title: '添加用户' }, { permission: 'admin.user.update', title: '修改用户' }, { permission: 'admin.user.destory', title: '删除用户' }, { permission: 'article.private.view', title: '查看加密文章' } ], grants: { superadmin: [], admin: [ 'admin.user.show', 'admin.user.store', 'admin.user.update', 'admin.user.destory', 'article.private.view' ], user: [], guest: [], }, } /** * 获取一个用户所属角色 * @param {Object} userId 用户ID */ async function getRoles(userId){ let sql = "SELECT * FROM tb_user_meta WHERE user_id=? AND meta_key='role'"; let [res] = await dbUtil.execute(sql, [userId]); let roles = res.map((item, index)=>{ return item.meta_value }); return roles; } /** * 获取一个用户所有角色权限的并集 * @param {Object} userId 用户ID */ async function getPermission(userId){ let roles = await getRoles(userId); let permissions = []; roles.forEach((item,index)=>{ permissions = permissions.concat(rbac.grants[item]); }); return permissions; } /** * 判断一个角色是否有某个权限 * @param {Object} roleName 角色名 * @param {Object} permission 标记 */ async function roleCan(roleName, permission){ let permissions = rbac.grants[roleName]; if(permissions == undefined){ return false; } return permissions.indexOf(permission) == '-1' ? false : true; } /** * 判断一个用户是否有某个权限 * @param {Object} userId 用户ID * @param {Object} permission 标记 */ async function can(userId, permission){ let rolePermission = await getPermission(userId); return rolePermission.indexOf(permission)=='-1' ? false : true; } export default { getRoles, getPermission, roleCan, can }
四,使用方法
import rbacUtil from './utils/rbac.util.mjs'; let userId = getUserId(); if( false == rbacUtil.can(userId, 'admin.user.destory') ){ ctx.status = 403; ctx.body = { error:"当前用户没有删除权限" }; return; }
修改时间 2023-11-02
声明:本站所有文章和图片,如无特殊说明,均为原创发布。商业转载请联系作者获得授权,非商业转载请注明出处。