一,简单的权限模型
有个访问权限列表如下:
用户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
声明:本站所有文章和图片,如无特殊说明,均为原创发布,转载请注明出处。