一、权限(Permission)
在与人沟通的过程中,我们很多次提到了权限,但是权限具体的含义每个人理解的含义都不明确,这样很容易造成双方信息不对称,有的人就只是把权限理解成某个页面的是否可访问,但是有的人却理解成其他的东西。
所以我们要彻底的定义一下权限是什么?
“权限”这个词语,我们谈论时到底是名词属性还是动词属性?这对于权限的含义很重要。
如果是名词属性的话,那么它应该是有具体的指代物;如果是动词,则应该具有行为表示。
- 权限的名词属性:api接口、页面、业务功能等。
- 权限的动词属性:可访问、新增、编辑、可操作、不可操作等。
那么我们现在来看,其实权限是名词、动词属性的综合,它表达了两层含义,即控制的对象及对象的操作。
因此,权限是控制对象(Object)与操作行为(Operation)的组合,具有双重属性:
属性类型 | 内容示例 | 典型场景 |
---|---|---|
名词属性 | API接口、页面、按钮、数据字段 | 系统菜单访问控制 |
动词属性 | 查看、新增、修改、删除 | 按钮操作权限控制 |
(一)控制对象(Object)
我们在授权时总是在说:要对哪些事物可以做什么的权限?
控制对象(Object)是系统所要保护的资源(Resource),可以被访问的对象,又称为权限对象、受控对象。
资源的定义需要注意以下两个问题:资源具有层次关系和包含关系。
1.资源的层次和包含关系
例如,网页页面是资源,网页页面上的按钮、文本框等对象也是资源。一级菜单的优先级高于二级菜单,菜单的优先级高于按钮,如可以访问按钮,则必须能够访问页面。
资源层次结构:页面 > 模块 > 按钮 > 字段
资源继承规则:子资源权限依赖父级资源权限
这些资源集中在一起,对每个资源设立自己的父编号,从而在进行优先级的选择和显示的时候,能按照正确的方式进行。
2.资源的类别与实例的区分
这里提及的资源概念是指资源的类别(Resource Class),不是某个特定资源的实例(Resource Instance)。
资源的类别和资源的实例的区分以及资源的粒度的细分,有利于确定权限管理系统和应用系统之间的管理边界,权限管理系统需要对于资源的类别进行权限管理,而应用系统需要对特定资源的实例进行权限管理。
两者的区分主要是基于以下两点考虑:一方面,资源实例的权限常具有资源的相关性。即根据资源实例和访问资源的主体之间的关联关系,才可能进行资源的实例权限判断。
资源类型:
资源类别(Class):客户档案(抽象概念)
资源实例(Instance):销售A的客户数据(具体数据)
例如,在销售管理系统中,需要按照营业区域划分不同部门的客户,销售A和销售B都具有修改客户资料这一受控的资源,这里“客户档案资料”是属于资源的类别的范畴。如果规定销售A只能修改销售A管理的客户资料,就必须要区分出资料的归属,这里的资源是属于资源实例的范畴。
客户档案(资源)本身应该有其使用者的信息(客户资料可能就含有营业区域这一属性),才能区分特定资源的实例操作,可以修改属于自己管辖的信息内容。
另一方面,资源的实例权限常具有相当大的业务逻辑相关性。对不同的业务逻辑,常常意味着完全不同的权限判定原则和策略。
(二)权限项(Ops)
抽象地来说,权限是对受保护的资源操作的访问许可(Access Permission),是绑定在特定的资源实例上的。
对应地,访问策略(Access Strategy)和资源类别相关,不同的资源类别可能采用不同的访问模式(Access Mode)。
例如,页面具有能打开、不能打开的访问模式,按钮具有可用、不可用的访问模式,文本编辑框具有可编辑、不可编辑的访问模式。同一资源的访问策略可能存在排斥和包含关系。
控制对象和访问策略的组合才能称为一项权限,因此,权限考虑各中资源,还要考虑各种操作,各操作项有时又称为权限项。
权限项的不同组合,也成就了角色的复杂多变,用户权限的千变万化。
1.各种操作
对待操作,大的范围包括:无、只读、编辑;而编辑又可以分为:增加,删除,更新等等,这些基本操作还可以进行不同情况的组合来满足多方面的需求。最终通过资源object和操作operate建立关系,形成权限(Permission)。
然而诸多的变化都来自这些最基本元素的的基本操作,即增加、修改、删除、查看。
对于实际应用而言,增加、修改的动作就是对资源数据进行“写”操作,而查看动作便是对资源数据进行“读”。
“读”、“写”、“删除”三者共同构成了对资源数据的全部操作。
(1)查看操作
“查看”操作是最为复杂的操作,也是四个操作里面最为核心的操作。“查看”动作就是调取符合条件的信息的资源数据。
“更改”和“删除”动作的第一步便是需要“查看”动作调取资源数据来作为它们的操作对象。
在“增加”资源数据时,一些系统基础数据也需要“查看”动作将数据调取出,方便和规范“增加”数据的操作。
故而“查看”动作便是其他动作在权限实现过程中的第一道关口。因此,“查看”动作关注如下几个方面内容:
- 第一,用户是否为该条资源信息的产生用户。
- 第二,用户的部门与所需查看信息的部门是否相匹配
- 第三,用户是否为所查看信息的特别专属用户。
以上便是对用户权限最基本单元权限项的简单分析,通过对基本操作对基础资源的划分来实现静态职责分离的约束。
通常,如果用户只拥有“读”资源数据的权限,而没有“写”和“删除”的权限,这种情况便是属于静态职责分离的约束。
同样,如果用户既拥有了“读”资源数据的权限,又拥有了“写”资源数据的权限,却不能“删除”,这时用户便是同时拥有“读写”权限,这便是没有进行静态职责分离的约束。而往往实际的工作中,面临的情况却是更为复杂。
(2)新增操作
就“增加”资源数据这个动作而言,便存在几种情况:
- 增加一条数据,此数据必须是完整的结构才能被增加。
- 增加一条不完整的数据,此数据可以不完成,同一用户可以完成“增加”的动作之后一段时间内进行继续完善信息的动作。
- 增加一条不完整的数据,此数据其后的内容,必须由另一用户在一定的时间段内完善。
(3)修改操作
“修改”的动作更为复杂,现可简单列举几个方面内容。
“修改”数据关注点主要涉及到以下几个方面:
第一,修改该条数据的时间要求。
第二,此条数据的修改是属于改正输入错误类型还是属于数据状态正常改变类型。“修改”的动作在业务流程可以代表很多内涵。
比如,在机车的整备过程中,可以是“机统-6 完成查验”、“合格证发放”、“附挂(回送)”及“机车出库”等诸多操作。
(4)删除操作
“删除”动作通常指的是标记删除。区别于物理删除,即不是真正意义上的删除,而是通过数据库中数据字段的特殊标记,使得这些被“删除”数据无法显示出来而已。
删除的动作其实就是特殊的“修改”操作。“删除”操作有两大主要内涵:
第一,对于错误数据的清除;
第二,在业务流程的流转环节中,对于数据的提交。数据进入下个流程中后,上一个流程便“删除”相应的数据。
这样使得系统的整个流程化更加清晰。
2.操作权限
操作权限就是将操作视为资源,比如删除操作,有些人可以,有些人不行。
对于服务端来说,操作就是一个接口。对于前端来说,操作往往是一个按钮,所以操作权限也被称为按钮权限,是一种细颗粒权限。
在页面上比较直观的体现就是没有这个删除权限的人就不会显示该按钮,或者该按钮被禁用:
前端实现按钮权限还是和之前导航菜单渲染一样的,拿当前用户的权限资源id和权限资源字典对比,有权限就渲染出来,无权限就不渲染。
操作权限其实是比页面权限安全的,为什么呢?
这个安全主要体现在服务端上,页面渲染不走服务端,由前端页面自己控制。但点击按钮的事件必须访问接口,必须得走服务端,我们只需要对每个接口进行权限判断就OK了!
二、功能权限和数据权限
软件系统的权限包含两部分:
- 功能权限,指各个角色可以操作的界面、按钮等,例如管理员可以进行新增、删除、修改等操作;运营人员在同样的页面上只能使用各种筛选条件查看数据,无法做更改。
- 数据权限,指各个角色在各页面中能看到的数据范围,例如分公司管理员在订单查询页能看到分公司的所有订单,而区域主管在订单查询页只能看到所在区域的订单。
(一)功能权限
功能权限是指用户能否操作某些功能的权限,简单来说就是用户能否点击系统中的某个按钮或链接(打开页面也是点击链接的一种)。
定义:用户能否使用特定功能的能力
1.功能权限的层次
根据权限不同层次的特点,功能权限的建立可以分为三个层次:数据层权限,业务层权限、表示层权限。
根据权限的三层结构分析,其内涵主要体现在对系统菜单的访问以及页面中的功能按钮控制,文件的修改控制以及页面上数据的可见性等。
实现层级:
数据层:数据库操作权限
业务层:API接口调用权限
表示层:UI元素可见性控制
在数据库的具体设计上,菜单、文件、页面元素可以归为一类,功能操作可以归为一类。
权限:对受保护的资源操作的访问许可(Access Permission)是绑定在特定的资源实例上的。
对应地,访问策略(Access Strategy)和资源类别相关,不同的资源类别可能采用不同的访问模式(Access Mode)。
在定义操作权限时,需要与查看权限相关联。
- 先有查看权限,才有操作权限。
- 取消了查看权限,就自动取消了操作权限。
- 当用户没有操作权限时,对应的操作按钮或链接最好隐藏,不要等到用户点击后才告诉他没有权限,即“可见即可用”。
2.检验权限的场景
触发验权有很多种情况,最常见的是以下五种:
- 获取当前用户有权的应用范围;
- 获取当前用户有权的菜单范围;
- 判断当前用户执行当前操作是否有权;
- 获取当前用户在当前应用当前表单的查询权下有权的隔离维度范围;
- 获取当前用户在当前应用当前表单下有权和无权的权限项的范围。
<!-- 按钮权限控制示例 -->
<button v-if="hasPermission('order:delete')