软件开发

如何建设一个权限系统

2018-08-15  本文已影响850人  骆宏

1.权限系统是什么

权限系统就是系统的安保系统,保障系统的功能谁能使用,谁可以操作哪些数据

2.权限系统的组成

决定了用户能够使用哪些功能

决定了用户能够使用哪些行数据

决定列用户能够查操作哪些列的数据

3.功能权限系统的实现方式

3.1.功能权限的粒度大小

3.2.如何实现细粒度的功能权限控制

3.3.RBAC(Role Base Acess Control)模型的介绍

权限模型

在授权时,把权限都集中收于给Role,然后将Role授予User,达到提高效率的一个方式,但是本质还是把权限授予给了具体的用户。

3.4.基于RBAC的衍生模型

RBAC衍生模型

衍生了用户组的概念

3.5.RBAC等模型的本质

无论模型怎么变化,但是最终的权限落地,都是将权限授予用户。在方案选型时,要关注业务的复杂度与哪种模型的匹配度较为吻合,切勿好高骛远,过度选型。

4.行数据权限

数据权限的实现,目前业界并无通用的解决方案,所以这里面主要是介绍一种模型,大家可以借助模型,去发现系统的数据权限模型

4.1识别权限实体

在做数据权限时,第一步就是要识别出权限实体。下面举几个例子

4.2.识别系统要做到哪种级别权限控制

4.3.数据存储的实现方式

方案1: [1000001,A]的数据需要存储在一个数据权限表中,我们叫他lh_auth_data,那么就存储一条[1000001,A]
方案2:直接把数据存储在lh_order即可,也就是jt_order中有一条积累[1000001,A]
这两个方案都可以,但是查询的性能会有却别

4.3.1.方案优缺点对比

方案1由于多了一个表,在查询时,可能会导致性能下降,但是却留了一个很好的扩展点,比如1000001同时支持B管理,只需要在lh_auth_data插入[1000001,B]
方案2查询性能较好,但是却扩展不易,假设需要支持B,那么将处理起来非常棘手

4.4.数据的sql查询模型

假设权限实体是:account、product_group、country

select xxx from xx_table where account in (xxx) and product_group in (xxx) and country in (xxx)

4.5.查询性能的问题

在4.4的查询模型中,我们发现使用的是in查询,我们都知道,mysql的in是有效率问题的,当数据规模来到kw级别时,上面的模型就会出现性能的极速下降。
为了突破该性能限制,我们借助tree,以及mysql的前置like查询


20180408123706965.png
A: 10
B: 10001
C: 10002
D: 10003
E: 10001001
F: 10001002
...

假设我们能够将权限实体,进一步的用tree来组织,然后将权限实体的in转换为tree key like '10001%'的模型,我们可以发现,即利用上了mysql的索引,又解决了in的效率问题。

4.5.1.小心tree的key陷阱

在上面,我们使用tree key来处理,但是我们注意到,tree key是有数量限制的,比如A的直接子节点,key范围是:[10001,99999],假设超过了该tree key时,需要考虑怎么进行数据保护。

5.列数据权限

5.1数据

我们先看一个简单的列子,用户管理,api返回的数据如下

[
    {
        "name": "骆宏",
        "age": 27,
        "tel": "15013336**4",
        "school": "广东海洋大学",
        "job": "高级开发工程师"
    },
    {
        "name": "骆宏",
        "age": 27,
        "tel": "15013336**4",
        "school": "广东海洋大学",
        "job": "高级开发工程师"
    }
]

5.2.前端界面的效果

对A用户,无权限控制的现实效果

名字 年龄 电话 学校 工作
骆宏 26 1380013800 广东海洋大学 高级java开发工程师

对B用户,age、tel无权限查看

名字 年龄 电话 学校 工作
骆宏 * * 广东海洋大学 高级java开发工程师

编辑界面同理,直接变成disabled即可

5.2.设计实现

实现主要有如下几个步骤

5.2.1.进行数据namespace

比如下面数据

{
    "name": "骆宏",
    "age": 27,
    "tel": "15013336**4",
    "school": "广东海洋大学",
    "job": "高级开发工程师"
}

借用功能权限的设计,给需要做列权限控制的数据,进行数据namespace,比如用户管理的namespace为user.module,可具备管理的key有name,age,tel,school,job

5.2.1.对数据进行授权

将用户管理(user.module)的name,age,tel,school,job访问权限授予角色A

5.2.1.获取权限上下文

将系统的所有权限,使用权限上下文抽象
上下文数据结构类似下面

{
    "name": "角色A",
    "用户列表": [1,2,3,4],
    "功能权限列表":["user.add","user.delete"],
    "行权限列表":["部门key1","部门key2","部门key3"],
    "列权限列表":[{    
            "name": "用户管理",
            "columns": "可以访问的列"
    }]          
}

5.2.1.后端过滤

在访问时,根据用户id,以及权限上下文,将无权限访问的key,设置为*

6.面对权限系统的变化

唯一不变的,只有变化。在建设系统时,有时候一开始并未能很直接的catch住核心业务,或者是核心业务本身也是变化的。所以在设计权限时,应该做到

6.权限代码的抽象

    DataAuthContext dataAuthContent = dataAuthContextService.getByUserId(userId);

7.写在最后

没有最完美的设计,只有最适合的设计。权限模型在建设系统时,是非常关键的一步,做好了,后面的人处理权限时,非常简单。如果做的不好,那么权限的代码就会遍布系统,遍布N个模块,重构过N个权限系统的我,苦不堪言...

谢谢大家看到最后,Thank you for you reading
参考链接:功能权限的设计
数据权限的设计

上一篇下一篇

猜你喜欢

热点阅读