多公司权限模型
多公司权限模型
光石头 发表于5年前
多公司权限模型
  • 发表于 5年前
  • 阅读 1108
  • 收藏 27
  • 点赞 0
  • 评论 25

新睿云服务器60天免费使用,快来体验!>>>   

此文转自我的个人博客:http://www.weicms.net/2012/12/17/quanxian.html

 

今天和一个网友争论了权限的问题,我感觉有必要分享下我的研究心得.

权限 无非是 角色 人员 资源 的配比关系

权限的操作无非是 增删改查,导入,导出 的操作,以及针对数据集的操作

业务结构无非是 公司,部门,用户

在rest时代,权限无非是 对一个URL是否有权限操作! 权限的本质就是URL的访问控制!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

-- ----------------------------

-- Table structure for `users`

-- 都是常用的字段

-- ----------------------------

DROPTABLEIF EXISTS `users`;

CREATETABLE`users` (

  `id`varchar(40)NOTNULL,

  `name`varchar(50)DEFAULTNULL,

  `userCode`varchar(50)NOTNULL,

  `password`varchar(50)NOTNULL,

  `email`varchar(100)DEFAULTNULL,

  PRIMARYKEY(`id`)

) ENGINE=InnoDBDEFAULTCHARSET=utf8;

 

---角色表

---角色是继承关系

---level,roleCode为表示层级关系,部门表类似.主要用于快速查询,抛弃递归函数.

DROPTABLEIF EXISTS `role`;

CREATETABLE`role` (

  `id`varchar(50)NOTNULLDEFAULT'',

  `pid`varchar(50)NOTNULLDEFAULT'',--父角色ID

  `roleName`varchar(200)NOTNULL,

  `level`intNOTNULLDEFAULT0,--角色处的层级,根角色为1,它的子角色为2 孙角色为3

  `roleCode`varchar(200)NOTNULL,--根角色001 他的子角色为001001,001002...孙角色为001001001,001002001....依次类推.

  PRIMARYKEY(`id`)

) ENGINE=InnoDBDEFAULTCHARSET=utf8;

 

-- ----------------------------

-- Table structure for `model`

-- ----------------------------

DROPTABLEIF EXISTS `model`;

CREATETABLE`model` (

  `id`varchar(50)NOTNULL,

  `modelName`varchar(200)NOTNULL,

  PRIMARYKEY(`id`)

) ENGINE=InnoDBDEFAULTCHARSET=utf8;

 

----

-- ----------------------------

-- Table structure for `re_user_role`用户角色中间表

-- ----------------------------

DROPTABLEIF EXISTS `re_user_role`;

CREATETABLE`re_user_role` (

  `id`varchar(50)NOTNULL,

  `userId`varchar(50)NOTNULL,

  `roleId`varchar(50)NOTNULL,

  PRIMARYKEY(`id`)

) ENGINE=InnoDBDEFAULTCHARSET=utf8;

 

--角色资源中间表

DROPTABLEIF EXISTS `re_role_model`;

CREATETABLE`re_role_model` (

  `id`varchar(50)NOTNULL,

  `roleId`varchar(50)NOTNULL,

 -- `startDate` datetime,

 -- `endDate` datetime,--表示权限的生存周期,用于领导临时分配权限,这里简化暂不讨论

 -- allunit int,--主要用于判断是否级联下级部门,这里不讨论

  `pageurl`varchar(1000)NOTNULL,

  `bool`int(11)NOTNULLDEFAULT'1',--表示真假,0为假,1为真

  PRIMARYKEY(`id`)

) ENGINE=InnoDBDEFAULTCHARSET=utf8;

基本表结构如此,其他例如 unit 什么的这里就不写了

说下场景,借用网友的一张图片啊
154119_GsbS_724215
这里要重点说下 re_user_model 中间表的pageurl 和bool字段

pageurl是一个正则表达式,用于匹配用户访问的URL .    bool表示真假,前提是pagurl必须匹配.

pageurl 和model表也没有直接关系了,只是一个正则表达式而已.

如果pagurl匹配时, bool=0表示不可访问,bool=1表示可以访问此url.例如 角色superuser 能够访问除了/admin/开头之外的所有url.就可以在数据库插入两条数据

1

2

INSERTINTO`re_role_model`VALUES('b1156249-9a8c-4f71-99ca-f56864401c41','superuser','(.*)','1');

INSERTINTO`re_role_model`VALUES('fa1f2c33-b5b8-4134-ae50-53334de61fc3','superuser','.*/admin/.*','0');

根据 bool字段正序查询

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

String model_sql="SELECT re.* FROM re_role_model as re,re_user_role as rerole 

where

re.roleId=rerole.roleId and rerole.userId=:userId order by re.bool asc";

 

//对比url是否匹配

booleanflag=false;

for(Re_Role_Model m:models){

String pageurl=m.getPageurl();

Integer bool=m.getBool();

Pattern pattern = Pattern.compile(pageurl);

Matcher matcher = pattern.matcher(requestURL);//请求的url是否具有权限

booleanf=matcher.matches();

if(f&&(bool==0)){//如果没有权限,跳出.

flag=false;

break;

}

 

if(f&&(bool==1)){

flag=true;

break;

}

}

returnflag;

这是整个控制的核心 访问的url是根据正则匹配的!!  通过rest 将数据权限转变成对URL的访问控制

系统依赖rest实现权限的控制

约定url如下 : /{model}/{operation}/{公司ID}/ 为标准开头

操作约定为 save/delete/update/get/import/export

我认为 公司拥有单独的组织结构,可以认为是根,所以单独列出.当然也可以根据业务需要去掉{公司ID}

例如 /user/update/abc/unit789/123  (/user/update/{公司ID}/{部门ID}/{userID})意义为 修改 abc公司下部门为unit789 id为123的员工信息

所有的角色都是从根角色派生而来(可以根据业务实际需要决定是否角色继承),根角色为 admin(超级管理员) 其他的角色都是依次派生 就和主管分配权限是一致的. 例如 superuser 派生自admin

1

2

insert into role values('admin','','超级管理员','1','001')

insert into role values('superuser','admin','超级用户','2','001001')

主管操作是一样的,这个其实用户前台操作比较复杂,后台理顺关系还是比较简单的.每个用户都可以从自己的权限范围内分给其他用户(其实也是角色,只是后台默认生成了)

关于re_role_model 中的 allunit 主要是用来判断是否包含子部门

例如 admin给 superuser分配了.*/user/get/gs123/unitabc/.*  (/user/get/{公司ID}/{部门ID}) 用来判断 superuser是否能够查询 unitabc下的所有子部门 如果unitabc下的部门较少 可以用多条记录代替 例如

..*/user/get/gs123/unitabc1/.*   .*/user/get/gs123/unitabc2/.*  如果子部门较多 可以启用 allunit 字段,根据实际情况自行判断吧

 

pageurl正则表达式,反转获得实际权限数据 可 以扩展实现数据库正则函数,在sql中直接对比.

示例

select u.* from unit as u ,re_role_model as re where regfun('/update/'+u.id+'/',re.pageurl,re.bool) and re.roleid='admin'

关于大家关心的sql注入我这里说下

1.会有过滤器过滤非法的url字符

2.如果你伪造了url 可以通过我的权限过滤器,但是却无法找到controller,404.例如 我的controller 接收路径为 /usr/update/abc  你给我发送了 /user/update/abc/d/c   controller无法相应此请求.

3.regfun这个函数的参数不是从前台获取的,而是根据业务逻辑后台拼装的!

----------------------------------------------------权限系统的思想基本介绍完毕了.--------------------------------

来个实例

添加管理员  admin_add  有全局添加权限  .*/save/.*  bool 为1.

当然也可以具体到某个公司,某个部门,某个人.也就是数据集权限

因为 有 bool 字段做判断. 可以很容易做出交叉权限,例如上例的superuser 除了/admin/其他的都有权限访问.

save/delete/update/get/import/export 其实代表了操作 可以根据需要添加角色的权限.角色是继承的,所以用户可以再自己的权限范围内 自由分配给其他用户.

当然有些也是可以系统定义的 例如

.*/user/delete/admin.* bool 为0 roleid为 *   任何角色都没有权限删除超级管理员的权限. 这些都是系统后台定义的.

最小权限.例如 普通用户 abc只有访问自己信息的权限

pageurl为:  */user/update/abc.*  (当然,这里可以使用二次解析的通配符,暂不讨论)

如果用户abc向非法修改 用户f的信息 那么访问的url是  */user/update/f.*     数据库没有匹配的url,没有权限访问

 

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
光石头
粉丝 312
博文 92
码字总数 17546
作品 2
评论 (25)
铂金小猪
坐等宏哥,不过我觉得有问题。
宏哥

引用来自“铂金小猪”的评论

坐等宏哥,不过我觉得有问题。

他没有资格得到我的评价
铂金小猪

引用来自“宏哥”的评论

引用来自“铂金小猪”的评论

坐等宏哥,不过我觉得有问题。

他没有资格得到我的评价

←_←低调宏哥。
光石头

引用来自“铂金小猪”的评论

引用来自“宏哥”的评论

引用来自“铂金小猪”的评论

坐等宏哥,不过我觉得有问题。

他没有资格得到我的评价

←_←低调宏哥。

什么问题呢?
pengcheng_1024
看来还是我的能力太差啊!!还是没搞明白!!需要好好学习!!看来我的机会来的有点早!!
pengcheng_1024
看来还是我的能力太差啊!!还是没搞明白!!需要好好学习!!看来我的机会来的有点早!!
光石头

引用来自“pengcheng_1024”的评论

看来还是我的能力太差啊!!还是没搞明白!!需要好好学习!!看来我的机会来的有点早!!

有一条一定要记住,不要使用递归函数,使用两个辅助字段 level 和 unitcode !我们上一代的权限体系就是参考了用友华为的系统,切记!!!! @宏哥 说mysql无法实现这样的权限控制,我简直无语了.......
光石头

引用来自“宏哥”的评论

引用来自“铂金小猪”的评论

坐等宏哥,不过我觉得有问题。

他没有资格得到我的评价

呵呵,你现在是个笑话了.
Backflow
这个设计里没有完全考虑到http的PUT, DELETE等方法吧, 对于同一个url地址, 不同的http方法对应的是不同的操作.. 你这里只是考虑了GET或是POST方法, 假REST...
光石头

引用来自“BackFLow”的评论

这个设计里没有完全考虑到http的PUT, DELETE等方法吧, 对于同一个url地址, 不同的http方法对应的是不同的操作.. 你这里只是考虑了GET或是POST方法, 假REST...

get post 只是我举例说明......具体业务你可以自行处理啊......
Backflow

引用来自“屁屁果”的评论

引用来自“BackFLow”的评论

这个设计里没有完全考虑到http的PUT, DELETE等方法吧, 对于同一个url地址, 不同的http方法对应的是不同的操作.. 你这里只是考虑了GET或是POST方法, 假REST...

get post 只是我举例说明......具体业务你可以自行处理啊......

那请问算上这PUT,DELETE方法的话怎么做权限控制呢? 上面的表设计没有考虑过这个问题呀..
光石头

引用来自“BackFLow”的评论

引用来自“屁屁果”的评论

引用来自“BackFLow”的评论

这个设计里没有完全考虑到http的PUT, DELETE等方法吧, 对于同一个url地址, 不同的http方法对应的是不同的操作.. 你这里只是考虑了GET或是POST方法, 假REST...

get post 只是我举例说明......具体业务你可以自行处理啊......

那请问算上这PUT,DELETE方法的话怎么做权限控制呢? 上面的表设计没有考虑过这个问题呀..

put delete 只是form的表单的提交方式,转换为url也就是 {operation},
文中已经介绍了啊:
约定url如下 : /{model}/{operation}/{公司ID}/ 为标准开头
操作约定为 save/delete/update/get/import/export
Backflow
加我Q吧, 我项目用到Rest好多权限问题都没解决... 求教导: 464961588
Backflow
我对这套设计方案有更好的建议, 加我QQ吧,讨论讨论呀...
Backflow
REST是把一个类如User类看作是一种资源, 对应的Controller为 '/user', 这是父路径, 对于资源下的所有操作应该大多数是可以共用的, 比如CRUD, 如 '/user/new', '/user/edit'等.
'/new'与'/edit'这是子路径, 对于每个一操作, 如果没有资源级的权限, 那么直接就pass掉, 形成了短路判断, 这样可以提高权限判断的效率... 大家说是不是, 所有这里是不是可以把资源和操作两种权限分开存储, 再来个中间关联表? 可行不?
王瑞平
理解浅了,遇到数据权限就崩溃了
比如销售人员分配销售电话,每个人只能操作自己分配到的数据
当一个销售离职了,数据收回再分配或者直接转交****
复杂的问题预先没有计划到时很多系统做到结束时发现失败的跟本原因
再考虑你的系统里有几百个各级管理员情况下怎么办
只考虑这一步也太简单
光石头

引用来自“王瑞平”的评论

理解浅了,遇到数据权限就崩溃了
比如销售人员分配销售电话,每个人只能操作自己分配到的数据
当一个销售离职了,数据收回再分配或者直接转交****
复杂的问题预先没有计划到时很多系统做到结束时发现失败的跟本原因
再考虑你的系统里有几百个各级管理员情况下怎么办
只考虑这一步也太简单

url可以非常复杂,然后加密成短url,例如新浪微博
光石头

引用来自“屁屁果”的评论

引用来自“王瑞平”的评论

理解浅了,遇到数据权限就崩溃了
比如销售人员分配销售电话,每个人只能操作自己分配到的数据
当一个销售离职了,数据收回再分配或者直接转交****
复杂的问题预先没有计划到时很多系统做到结束时发现失败的跟本原因
再考虑你的系统里有几百个各级管理员情况下怎么办
只考虑这一步也太简单

url可以非常复杂,然后加密成短url,例如新浪微博

每个数据都是一条url,然后销售人员拥有这些url的权限
哈库纳

引用来自“屁屁果”的评论

引用来自“pengcheng_1024”的评论

看来还是我的能力太差啊!!还是没搞明白!!需要好好学习!!看来我的机会来的有点早!!

有一条一定要记住,不要使用递归函数,使用两个辅助字段 level 和 unitcode !我们上一代的权限体系就是参考了用友华为的系统,切记!!!! @宏哥 说mysql无法实现这样的权限控制,我简直无语了.......

嗯,使用 递归函数 容易引发死循环,level unitcode 这种设计推荐。
哈库纳

引用来自“屁屁果”的评论

引用来自“屁屁果”的评论

引用来自“王瑞平”的评论

理解浅了,遇到数据权限就崩溃了
比如销售人员分配销售电话,每个人只能操作自己分配到的数据
当一个销售离职了,数据收回再分配或者直接转交****
复杂的问题预先没有计划到时很多系统做到结束时发现失败的跟本原因
再考虑你的系统里有几百个各级管理员情况下怎么办
只考虑这一步也太简单

url可以非常复杂,然后加密成短url,例如新浪微博

每个数据都是一条url,然后销售人员拥有这些url的权限

数据权限中 查看权限如何实现。 就是说不让列表中出现不想看到的数据。

资源是定义到业务表上,还是另起一个资源管理表。 感觉数据权限这块还是没有办法全面控制,建议数据权限彻底分离出去。
×
光石头
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: