你:我看完能知道个啥?
我:也就以下两点吧
一. 了解基于 RBAC 思路的表设计
二. 表数据在实际开发场景中是如何使用的
你:我觉得那应该还有点干货吧
我:我不要你觉得,我要我觉得 (͡ ͡° ͜ つ ͡͡°)

丹尼尔:Hi,蛋兄,最近接到需求,需要在已有的项目加上权限相关的功能,想想我专心混前端都好久了,N久没碰表设计了,你对这些有了解吗?

蛋先生:[]~( ̄▽ ̄)~* 略懂略懂~!已有项目,那就是不能“随心所欲”咯。说吧,关于已有项目DB的相关信息

丹尼尔:数据库是用MySQL,连接数据库用的是Sequelize, 一个ORM的Node.js库。

蛋先生:OK,这种组合搭配建议的流程是:先用EER图工具(如MySQLWorkbench)设计表结构,然后导出SQL,最后通过 Sequelize-Auto 自动生成 Model

丹尼尔:可以啊蛋兄,自动生成SQL,自动生成 Model。好久不见,你还是那么的懒啊 (\^▽^ )。你这么随便一说,就已经解决了我第一个问题了。那我们接着聊权限设计这块吧


RBAC表设计

丹尼尔:权限设计,这一块复杂吗?

蛋先生:要想多复杂就能多复杂,你想要什么样的难度系数的?<( ̄ˇ ̄)/

丹尼尔:不不不,我要既简单又灵活,可以灰常容易扩展那种的 ʅ(´◔౪◔)ʃ

蛋先生:要求挺高的嘛。现在这一块业界用的较多的是RBAC(Role-based access control)的思路,即基于角色的存取控制。话不多说,我直接上图吧

思路非常简单,就是只需给用户赋角色,而角色就决定了可以对什么资源(Resource)进行什么样的操作(Operation),Operation一般就是CRUD

丹尼尔:users 表为啥没 password 啊,为啥 code 什么都是 varchar(45) 啊

蛋先生:喂喂,先不要在意这些细节好吗?ヘ(・_|

丹尼尔:好好好。这表设计看上去挺简单的,行不行啊?

蛋先生:来,根据你的实际场景,请出招吧


功能权限

丹尼尔:假设有用户A和用户B;系统中有项目管理,用户管理两个功能;用户A是管理员,两个功能都能访问。而用户B是普通用户,只能访问项目管理,怎么弄?

蛋先生:小意思。┏ (\^ω^)=☞

1. 创建数据

  • 创建资源数据:项目管理,用户管理是属于功能模块级别的资源,数据如下:
  1. // resources:
  2. { code: 'projects', name: 'projects', type: 'module' },
  3. { code: 'users', name: 'users', type: 'module' },
  • 创建角色并赋予相关操作权限
  1. // roles:
  2. { code: 'admin', name: 'admin' },
  3. { code: 'guess', name: 'guess' },
  4.  
  5. // role_permissions:
  6. { roleCode: 'admin', resourceCode: 'projects', operation: 'create' },
  7. { roleCode: 'admin', resourceCode: 'projects', operation: 'delete' },
  8. { roleCode: 'admin', resourceCode: 'projects', operation: 'read' },
  9. { roleCode: 'admin', resourceCode: 'projects', operation: 'update' },
  10. { roleCode: 'admin', resourceCode: 'users', operation: 'create' },
  11. { roleCode: 'admin', resourceCode: 'users', operation: 'delete' },
  12. { roleCode: 'admin', resourceCode: 'users', operation: 'read' },
  13. { roleCode: 'admin', resourceCode: 'users', operation: 'update' },
  14. { roleCode: 'guess', resourceCode: 'projects', operation: 'read' },
  • 创建用户并赋予相应角色
  1. // users:
  2. { code: 'user_a', name: 'user_a' },
  3. { code: 'user_b', name: 'user_b' },
  4.  
  5. // user_role:
  6. { userCode: 'user_a', roleCode: 'admin' },
  7. { userCode: 'user_b', roleCode: 'guess' },

2. 消费数据

现在我们来给前端童学提供下数据来确定用户A能看到哪些功能模块,以及要不要显示创建,删除等按钮

  1. SELECT
  2. u.code userCode,
  3. res.code resourceCode,
  4. GROUP_CONCAT(rp.operation) operations
  5. FROM
  6. resources res,
  7. role_permissions rp,
  8. roles r,
  9. user_role ur,
  10. users u
  11. WHERE
  12. res.code = rp.resource_code
  13. AND rp.role_code = r.code
  14. AND r.code = ur.role_code
  15. AND ur.user_code = u.code
  16. AND res.type = 'module'
  17. AND u.code = 'user_a'
  18. GROUP BY u.code , res.code

得到的 user_a 的权限如下:

userCode resourceCode operations
user_a projects read,delete,update,create
user_a users delete,update,create,read

这样,前端只需判断 projects 是否拥有 read 的 operation,即可决定是否显示项目功能菜单。如果有 create,则显示创建按钮;有 delete,则显示删除按钮;有 update,则显示编辑按钮

3. 视图简化

丹尼尔:问题是解了,但那SQL,是不是有点复杂啊 (~ ̄▽ ̄)~

蛋先生:额,确实。那就来简化一下吧。

通过以下SQL创建用户功能模块权限的视图view

  1. CREATE VIEW `user_module_view` AS
  2. SELECT
  3. u.code user_code, rp.resource_code, rp.operation, rp.op_modifier
  4. FROM
  5. role_permissions rp,
  6. users u,
  7. user_role ur,
  8. resources rs
  9. WHERE
  10. ur.role_code = rp.role_code
  11. AND u.code = ur.user_code
  12. AND rs.code = rp.resource_code
  13. AND rs.type = 'module'

现在我们就可以把刚刚上面冗长的SQL简化成以下的单表操作了:

  1. SELECT
  2. user_code, resource_code, GROUP_CONCAT(operation) operation
  3. FROM
  4. user_module_view
  5. WHERE
  6. user_code = 'user_a'
  7. GROUP BY user_code , resource_code

数据权限

丹尼尔:那我继续出题咯。用户A和用户B虽然都对项目管理功能有 read 权限,但用户B是普通用户,假设用户B属于OrgB组织,那他就只能查看OrgB下的项目时该昨弄?

蛋先生:还记得 role_permission 的 op_modifier 字段吗,这就是用来修饰 operation 的。现在我们修改下 role_permission 的数据

  1. { roleCode: 'guess', resourceCode: 'projects', operation: 'read' }
  2. =>
  3. { roleCode: 'guess', resourceCode: 'projects', operation: 'read', op_modifier: 'org' },

这表示 guess 角色对 projects 资源拥有 org 范围的 read 权限。这样当服务端接口在取项目列表数据时,可以根据 op_modifier 的值来决定列表数据的过滤条件


丹尼尔:常规的需求好像都没什么问题。不过我现在这边有个权限相关的需求,不知道你这套能不能派上用场

蛋先生:来吧,我今天就奉陪到底了 ( ̄︶ ̄)

丹尼尔:那我就不客气了。我的项目管理功能中,每个项目创建后都默认有 view / edit / admin 角色。上面的例子只能对指定范围(比如org)的项目作相同的操作,但不同项目指定不同的操作,好像实现不了

蛋先生:[]~( ̄▽ ̄)~* 那就换个角度呗,把每一个项目都当作资源怎么样。

丹尼尔:能说得具体一些吗?最好能说下创建项目的时候权限这块该做些什么

蛋先生:咳咳咳~,没问题,来咯

按你的要求,在创建项目时,就需要初始化相应的内置角色,这样才能给用户分配角色。下面就说下假设创建项目project_a,需要给哪些表增加哪些数据

  1. // 1. add resource:
  2. { code: 'project_a', name: 'project_a', type: 'project' }
  3.  
  4. // 2. add roles:
  5. { code: 'pro_a_view', name: 'pro_a_view' },
  6. { code: 'pro_a_edit', name: 'pro_a_edit' },
  7. { code: 'pro_a_admin', name: 'pro_a_admin' },
  8.  
  9. // 3. add role_permission:
  10. { roleCode: 'pro_a_view', resourceCode: 'project_a', operation: 'read' },
  11. { roleCode: 'pro_a_edit', resourceCode: 'project_a', operation: 'read' },
  12. { roleCode: 'pro_a_edit', resourceCode: 'project_a', operation: 'update' },
  13. { roleCode: 'pro_a_admin', resourceCode: 'project_a', operation: 'read' },
  14. { roleCode: 'pro_a_admin', resourceCode: 'project_a', operation: 'update' },
  15. { roleCode: 'pro_a_admin', resourceCode: 'project_a', operation: 'delete' },

这样只需要给用户B增加pro_a_view角色,用户B即拥有对 project_a 的读权限

注意这里operation并没有create,因为资源是指单个项目,所以单个项目哪来的create呢?是吧 (\^▽^ )


丹尼尔:恩,看上去跟整个项目功能作为资源的时候是一个样的。但我发现个问题,如果以每个项目作为资源,那我要查询用户B能看到哪些项目,好像很麻烦啊。总不能一个一个找,然后合在一起吧

蛋先生:当然,还记得上面我们用过视图view吗?现在我们也给 project 类型的资源创建个view吧

  1. CREATE VIEW 'user_project_view' AS
  2. SELECT
  3. u.code user_code, rp.resource_code, rp.operation, rp.op_modifier
  4. FROM
  5. role_permissions rp,
  6. users u,
  7. user_role ur,
  8. resources rs
  9. WHERE
  10. ur.role_code = rp.role_code
  11. AND u.code = ur.user_code
  12. AND rs.code = rp.resource_code
  13. AND rs.type = 'project'

这样同样只需单表就能查询用户B能查看的项目列表以及每个项目的操作权限了

  1. SELECT
  2. user_code, resource_code, GROUP_CONCAT(operation)
  3. FROM
  4. user_project_view
  5. WHERE
  6. user_code = 'user_b'
  7. GROUP BY user_code , resource_code
  8. HAVING GROUP_CONCAT(operation) LIKE '%read%'

丹尼尔:哎呦不错。我还有最后一个需求,就是项目中的图片资源,如果用户B对 project_a 拥有 edit 角色,则只能删除自己添加的图片资源,不能删除其他人添加的图片资源,这个能实现吗。图片资源我可不想再像项目一样作为资源记录哦

蛋先生:(lll¬ω¬) 这个嘛...

丹尼尔:看来难倒你了,哈哈

蛋先生:非也非也。强大的op_modifier可不是吃素的。我只需对edit角色的update操作权限增加limited的修饰符即可

丹尼尔:这都行,好像有道理哦。由于op_modifier可以扩展,所以只要我们规定了它的行为,好像什么都可以搞定一样

蛋先生:All right。扩展性是一定要具备的,而op_modifier就是扩展的关键所在。op_modifier定义了操作的修饰符,开发者根据修饰符的约定,实现指定逻辑即可

丹尼尔:明白了,谢了,蛋兄,告辞告辞

蛋先生:客气客气,走好不送!

聊聊简单又灵活的权限设计(RBAC)的更多相关文章

  1. 产品设计-后台管理权限设计RBAC

    最近在做OA系统,设计到不同的员工会拥有不同权限对OA进行操作,总结了一下整体的设计 做权限的分配就是为了更好的管理不同类别的员工,如人事部可以看到普通员工的薪酬,可以查看全部员工的考勤数据请假等,而 ...

  2. SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

    SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建 技术栈 : SpringBoot + shiro + jpa + freemark ,因为篇幅原因,这里只 ...

  3. RBAC 权限设计(转载)

    来源 :https://blog.csdn.net/rocher88/article/details/43190743 这是我在网上找的一些设计比较好的RBAC权限管理 不知道,像新浪.搜狐.网易.百 ...

  4. 【权限设计】一个案例,三个角色,简单说下B端产品的权限设计

    入行以来也接触过一些B端产品,这些产品之中权限管理是重中之重,权限管理不仅仅是整个系统的一个小小的模块,它一直贯穿整个系统,从登陆到操作到最后的登出.说它相当的复杂真不为过. 对于权限,如果从控制力来 ...

  5. 百万年薪python之路 -- RBAC角色权限设计

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...

  6. yii2的权限管理系统RBAC简单介绍

    这里有几个概念 权限: 指用户是否可以执行哪些操作,如:编辑.发布.查看回帖 角色 比如:VIP用户组, 高级会员组,中级会员组,初级会员组 VIP用户组:发帖.回帖.删帖.浏览权限 高级会员组:发帖 ...

  7. 基于RBAC的权限设计模型

    个部件模型组成,这4个部件模型分别是基本模型RBAC0(Core RBAC).角色分级模型RBAC1(Hierarchal RBAC).角色限制模型RBAC2(Constraint RBAC)和统一模 ...

  8. ASP.NET -- WebForm -- Cookie的使用 应用程序权限设计 权限设计文章汇总 asp.net后台管理系统-登陆模块-是否自动登陆 C# 读写文件摘要

    ASP.NET -- WebForm -- Cookie的使用 ASP.NET -- WebForm --  Cookie的使用 Cookie是存在浏览器内存或磁盘上. 1. Test3.aspx文件 ...

  9. JAVA 数据权限设计

    数据权限设计 前言 在各种系统中.要保证数据对象的安全性以及易操作性,使企业的各业务部门.职能部门可以方便并且高效的协同工作,那么一个好的数据权限管理设计就成为一个关键的问题.尽管企业中各个单元的工作 ...

随机推荐

  1. python模块之----subprocess

    例子 >>> subprocess.getstatusoutput('pwd')(0, '/home/ronny')>>> subprocess.getoutput ...

  2. Django设置前端背景图片

    设置 setting.py 文件 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static&qu ...

  3. [Codeforces1174B]Ehab Is an Odd Person

    题目链接 https://codeforces.com/contest/1174/problem/B 题意 给一个数组,只能交换和为奇数的两个数,问最终能得到的字典序最小的序列. 题解 内心OS:由题 ...

  4. [程序员代码面试指南]二叉树问题-找到二叉树中的最大搜索二叉树(树形dp)

    题意 给定一颗二叉树的头节点,已知所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这个树的头节点. 题解 在后序遍历过程中实现. 求解步骤按树形dp中所列步骤.可能性三种:左子树最大.右子 ...

  5. WeihanLi.Npoi 1.10.0 更新日志

    WeihanLi.Npoi 1.10.0 更新日志 Intro 上周有个网友希望能够导入Excel时提供一个 EndRowIndex 来自己控制结束行和根据字段过滤的,周末找时间做了一下这个 feat ...

  6. python的多种魔术方法

    目录 new str & repr iter getitem.setitem.delitem getattr.setattr.delattr call slots 定制类和魔法方法 new s ...

  7. 盘点MySQL中比较实用的函数

    之前小编在工作中遇到一些处理数据的问题,例如完成日期格式化,获取几天后的时间,生成指定格式的编码等问题,这时候小编经常会写一大堆逻辑代码来进行处理,还自己感觉自己很流弊的样子,后来却发现同事遇到相同的 ...

  8. 优雅的在React组件中注册事件

    前言 在React的开发中,我们经常需要在 window 上注册一些事件, 比如按下 Esc 关闭弹窗, 按上下键选中列表内容等等.比较常见的操作是在组件 mount 的时候去 window 上监听一 ...

  9. 谈谈数据库的事务ACID

    在数据库中新建一个字段并且设置为索引列,还有删除整张表的数据,类似这些操作都是一系列操作的组合,执行后不能出现中间状态,也就是不会出现新建了字段却不是索引的情况,也不会出现只有一部分数据被删除的情况. ...

  10. 【学习笔记】Polya定理

    笔者经多番周折终于看懂了\(\text{Burnside}\)定理和\(\text{Polya}\)定理,特来写一篇学习笔记来记录一下. 群定义 定义:群\((G,·)\)是一个集合与一个运算·所定义 ...