转载本文需注明出处:微信公众号EAWorld,违者必究。
引言:
权限控制在每一个应用中都必不可少,类似却又总不尽相同。有没有一种比较通用的设计甚至框架,可让咱们不用每次都去重复造这个轮子呢?本文主要是向你们介绍下咱们的应用基础框架coframe,以及在权限控制方面的一些设计与实践。
目录:
1、应用基础框架简介
2、应用权限模型设计
3、应用权限控制
1、应用基础框架简介
相信不少同窗都有过这样的经历,刚作完一个项目,开始一个新项目的时候,发现基础能力又要从新开发一遍,用户,登录,菜单,机构人员,权限管理等等。重复的工做枯燥而没有价值,却不得不作。可否来个什么框架,能够直接提供这些开箱即用的基础能力?
回答固然是有,咱们这里把这种包含了应用基础能力与通用业务模块的框架,称之为应用基础框架。它就像一个半成品的车架,已经有了基本的架子,轮子,发动机,方向盘等,基本上已经能够跑了。可是车子更多的其它能力,还等待人后续去完善。
完整的应用基础框架,应当包括应用后端基础框架与前端展示基础框架(包括 web 或移动)。这样二者配合使用,才能直接为应用提供开箱即用的业务能力。
不论先后端,咱们认为框架能够分为如下四层:
1.基础依赖层:基本上定义的框架的技术栈,采用什么语言,什么框架,依赖哪些基础库或组件等
2.基础能力层:定义的是基础能力,后端包括对异常的定义,国际化的处理,ORM模型的抽像等等,前端则是对菜单,路由,通讯等的框架化封装,通用基础组件的抽取等
3.通用业务层:实现通用的一些业务能力,如用户管理,登入登出,权限控制等等
4.用户业务层:这一层交由用户去扩展,实现各自已的业务能力
Coframe就是咱们构建的这样一套应用基础框架。它的后端框架,基于 spring boot + spring security + jpa, 前端基于 vue + iview。
前端
Coframe应用基础框架能力图谱vue
coframe提供的基础能力有:
1.组织机构:机构树管理,机构管理,岗位管理,工做组管理,员工管理
2.用户认证:用户管理,本地认证,单点登录(需与 iam 集成)
3.权限管理:权限模板管理,角色模板管理,角色管理,资源组管理,菜单管理,功能管理
4.数据字典:字典类型管理,字典项管理,字典国际化,导入导出
5.日志管理:统一日志接口,日志全索
全部这些能力开箱即用。
下面咱们重点分享一下关于应用权限方面咱们的一些设计与实践
2、应用权限模型设计
首先,咱们要了解一下,什么是权限。咱们认为,权限就是用户对某些资源的控制能力。因此,模型上咱们就有了一个抽像的资源概念。
资源按类型具化,多是用户在门户上可见的菜单,或者是页面上可见可点击的某些按钮,或者用户在应用后端能够调用的某个接口等。
用户经过角色,与这些资源创建了关联,咱们才能在系统中经过用户找到这些资源,而后对它进行控制。
所以,用户,角色,资源的关系,就是一个用户可分配多个角色,一个角色,能够关联多个资源。以下图所示:
为了方便角色进行资源受权的管理,咱们又提出了几个服务于它们的概念:角色模板,权限模板,资源组。
资源组,顾名思义,就是资源的分组。它是一个树状模型,目前主要设计使用了三层。顶层的表明着某一块的资源总集,好比某个子系统的资源总集。
权限模板,它经过关联多个顶层的资源组,能够表明着某个范围内的可受权资源总集。角色模板关联着权限模板,从它的这个资源集合中挑出了一部分。
角色则是在建立的时候,复制模板的这些资源受权。但它后续能够修改,整个可受权资源仍为权限模板表明的总集。
资源的受权如上图所示。顶层的资源组表明着某一块的资源总集,第二层则表明不一样的资源类型,如菜单,功能,环境等。第三层表明着模块,好比机构管理模块的菜单。第三层的资源组之下,才关联具体的资源。对角色或者角色模板进行资源受权配置时,只须要找到对应的资源类型与模块,再找到相应的资源,点击是否勾选便可完成受权,很是地直观。
用户是如何与资源关联起来的呢?以下图,这里咱们假设了一个示例。
某应用集成了 coframe,其下又分了三个子系统。为了方便资源的管理,咱们为每一个子系统设置了一个顶层的资源组,而后为它配置了下层资源组与资源。而后,咱们设置了两个权限模板,其中一个负责 coframe 与子系统一的资源,另外一个则负责三个子系统的资源。基于两个权限模板,咱们分别建立了角色一与角色二。三个用户中,用户一分配了角色一,用户二分配了角色一与二,用户三分配了角色二。用户一可分配 coframe 与子系统一中的资源,用户二可分配全部资源,用户三则只能分配三个子系统的资源。这样,资源的组合与隔离,会变得至关方便与直观。
3、应用权限控制
咱们认为,应用的权限控制能够分为以下四类:
1.菜单:用户在应用门户中可见哪些菜单能够经过权限控制
2.按钮/连接:用户在门户页面中,哪些按钮可见可操做,可经过权限控制
3.接口调用:不经过门户,直接经过客户端进行接口调用,接口是否容许调用能够经过权限控制
4.数据:用户是否可见某些数据,可否操做能够经过权限控制
菜单控制
菜单的控制其实比较简单。用户登录成功后,前端会再来取一次用户的菜单项。后端服务根据用户分配的角色中,包含的菜单资源,在门户中组织出他所持有的菜单树。
可是菜单的组织过程,却也能够有一些不一样。这里咱们一种称为动态结构,另外一种为静态结构。
动态结构首先要求菜单自己为树状结构,且菜单对应的页面(vue 中叫路由),图标等也记录在菜单中。整个菜单的层次结构,由菜单自己的树状结构表现。这种结构的好处是菜单配置很是灵活,菜单能够彻底经过页面操做进行定制。这种结构适合常常须要动态变动的系统,且菜单配置人员对前端要很是地熟悉。
另外一种静态菜单结构,则菜单只须要一个平铺关系便可。菜单的层级,顺序,路由,图标等由前端定义,后端只定义用户能够用到哪些菜单。缺点是菜单定制不够灵活,但优势也很明显,很是便于前端开发,先后端分工更明确。
按钮/连接控制
有些系统中,会将按钮的权限与后端功能的权限分开设计为两个模型,但 coframe 中这两个合为一个叫作功能的模型。功能有惟一编码,这个编码在按钮上可控制按钮的显示,在方法上能够控制方法可否调用。
按钮的控制也比较简单,特别是组件化的前端开发框架中。只须要为全部的按钮组件添加一个权限码定义,在页面渲染时,判断一下当前用户是否拥有这个权限码,有则显示此按钮,没有则将按钮从父组件中删除。
接口调用控制
在接口调用控制上,咱们考虑过使用现成的一些控制方法,如 spring method security。可是它只能控制到角色级,虽然能够规则匹配,但仍然不够灵活。因此,咱们基于功能编码,自行设计了一套。
它的基本原理是,咱们使用 annotation,在每一个须要控制的方法,添加了调用此方法须要的功能编码。方法被调用时,咱们经过 aspect 对方法进行拦截,取得调用它所要求的功能码。而后咱们在当前用户所拥有全部的功能码(在用户登录时已查询出来放在 context 中了)中进行对比,若是存在就容许方法调用,不然抛出无权调用的异常。
鉴于有些须要控制的方法可能在父类中,因此咱们定义了两个 annotation,一个定义在类上,能够配置父类上须要控制的方法。另外一个定义在方法上,配置方法控制的权限码。查询方法调用所需权限码时,优先在方法上找到,找不到再到类上去查找。
为了方便集成的应用实现接口调用控制,咱们定义了一个抽象的方法权限切片处理类,封装了对方法调用的拦截过程。应用只须要继承这个类,配置须要拦截哪些接口便可。
数据权限控制
数据权限,咱们认为数据权限 = 数据可见控制 + 数据操做控制。
而数据操做控制,经过按钮控制与接口调用控制组合,基本上可达到想要的效果。
那数据可见如何控制呢?咱们概括为两种:成员法与资源受权法。
成员法,就是用户若是为某个领域的成员,则他就能够看到这个领域,以及这个领域中的资源。如何实现呢?简单一点的办法,就是用户的某个角色,属于这个领域,就能够认为这个用户是这个领域的成员。像租户隔离,devops 中的项目隔离,其实就是用的这种方法。
资源受权法,将某个精确的资源受权角色,或者直接授予用户。成员法实现数据可见控制有一个问题,就是粗度太大,很差实现更精确更细粒度的资源可见控制。要实现更细粒度的,可使用资源受权法。但粒度细也就表明着管理复杂,孰好孰坏须要权衡后去使用。
关于做者:秦双春,现任普元云计算架构师。曾在PDM,云计算,数据备份,移动互联相关领域公司工做,十年以上IT工做经验。曾为科企桌面虚拟化产品的核心工程师,爱数容灾备份云柜系统设计师,万达信息的食安管理与追溯平台开发经理。国内IAAS云计算的早期实践者,容器技术专家。
关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享。长按二维码关注!web