《架构世界》2020微服务刊:微服务分布式事务实战
上QQ阅读APP看书,第一时间看更新

三、应用权限控制

我们认为,应用的权限控制可以分为如下四类:

1菜单:用户在应用门户中可见哪些菜单可以通过权限控制

2按钮/链接:用户在门户页面中,哪些按钮可见可操作,可通过权限控制

3接口调用:不通过门户,直接通过客户端进行接口调用,接口是否允许调用可以通过权限控制

4数据:用户是否可见某些数据,能否操作可以通过权限控制

菜单控制

菜单的控制其实比较简单。用户登陆成功后,前端会再来取一次用户的菜单项。后端服务根据用户分配的角色中,包含的菜单资源,在门户中组织出他所持有的菜单树。

但是菜单的组织过程,却也可以有一些不同。这里我们一种称为动态结构,另一种为静态结构。

动态结构首先要求菜单本身为树状结构,且菜单对应的页面(vue中叫路由),图标等也记录在菜单中。整个菜单的层次结构,由菜单本身的树状结构表现。这种结构的好处是菜单配置非常灵活,菜单可以完全通过页面操作进行定制。这种结构适合经常需要动态变更的系统,且菜单配置人员对前端要非常地熟悉。

另一种静态菜单结构,则菜单只需要一个平铺关系即可。菜单的层级,顺序,路由,图标等由前端定义,后端只定义用户可以用到哪些菜单。缺点是菜单定制不够灵活,但优点也很明显,非常便于前端开发,前后端分工更明确。

按钮/链接控制

有些系统中,会将按钮的权限与后端功能的权限分开设计为两个模型,但coframe中这两个合为一个叫做功能的模型。功能有唯一编码,这个编码在按钮上可控制按钮的显示,在方法上可以控制方法能否调用。

按钮的控制也比较简单,特别是组件化的前端开发框架中。只需要为所有的按钮组件添加一个权限码定义,在页面渲染时,判断一下当前用户是否拥有这个权限码,有则显示此按钮,没有则将按钮从父组件中删除。

接口调用控制

在接口调用控制上,我们考虑过使用现成的一些控制方法,如spring method security。但是它只能控制到角色级,虽然可以规则匹配,但仍然不够灵活。所以,我们基于功能编码,自行设计了一套。

它的基本原理是,我们使用annotation,在每个需要控制的方法,添加了调用此方法需要的功能编码。方法被调用时,我们通过aspect对方法进行拦截,取得调用它所要求的功能码。然后我们在当前用户所拥有所有的功能码(在用户登陆时已查询出来放在context中了)中进行对比,如果存在就允许方法调用,否则抛出无权调用的异常。

鉴于有些需要控制的方法可能在父类中,所以我们定义了两个annotation,一个定义在类上,可以配置父类上需要控制的方法。另一个定义在方法上,配置方法控制的权限码。查询方法调用所需权限码时,优先在方法上找到,找不到再到类上去查找。

为了方便集成的应用实现接口调用控制,我们定义了一个抽象的方法权限切片处理类,封装了对方法调用的拦截过程。应用只需要继承这个类,配置需要拦截哪些接口即可。

数据权限控制

数据权限,我们认为数据权限 = 数据可见控制 + 数据操作控制。

而数据操作控制,通过按钮控制与接口调用控制组合,基本上可达到想要的效果。

那数据可见如何控制呢?我们归纳为两种:成员法与资源授权法。

成员法,就是用户如果为某个领域的成员,则他就可以看到这个领域,以及这个领域中的资源。如何实现呢?简单一点的办法,就是用户的某个角色,属于这个领域,就可以认为这个用户是这个领域的成员。像租户隔离,devops中的项目隔离,其实就是用的这种方法。

资源授权法,将某个精确的资源授权角色,或者直接授予用户。成员法实现数据可见控制有一个问题,就是粗度太大,不好实现更精确更细粒度的资源可见控制。要实现更细粒度的,可以使用资源授权法。但粒度细也就代表着管理复杂,孰好孰坏需要权衡后去使用。


推荐阅读

普元容器云关键设计和实践之路

容器时代的DevOps部署

有状态容器实践:k8s集成ceph分布式存储


关于作者:将晓渔,现任普元信息云计算架构师。曾在PDM,云计算,数据备份,移动互联相关领域公司工作,十年以上IT工作经验。国内IAAS云计算的早期尝鲜者,容器技术专家,微服务架构的践行者。