权限系统设计

权限系统(3)-- subject

 

权限控制中,subject可能不会简单的对应于userId, 而是包含一系列的security token或certificate, 例如用户登陆地址,登陆时间等。一般情况下,这些信息在权限系统中的使用都是很直接的,不会造成什么问题。
subject域中最重要的结构是user和role的分离,可以在不存在user的情况下,为role指定权限。有人进一步定义了userGroup的概念,可以为userGroup指定role,而user从其所属的group继承role的设置。一般情况下,我不提倡在权限系统中引入userGroup的概念。这其中最重要的原因就是它会造成多条权限信息传递途径,从而产生一种路径依赖, 并可能出现信息冲突的情况。一般user与group的关联具有明确的业务含义,因而不能随意取消。如果我们希望对user拥有的权限进行细调,除去user从group继承的某个不应该拥有的权限,解决的方法很有可能是所谓的负权限,即某个权限条目描述的是不能做某某事。负权限会造成各个权限设置之间的互相影响,造成必须尝试所有权限规则才能作出判断的困境,引出对额外的消歧策略的需求,这些都极大的限制了系统的可扩展性。在允许负权限的环境中,管理员将无法直接断定某个权限设置的最终影响,他必须在头脑中完成所有的权限运算之后才能理解某用户最终拥有的实际权限,如果发现权限设置冲突,管理员可能需要多次尝试才能找到合适方案。这种配置时的推理需求可能会增加配置管理的难度,造成微妙的安全漏洞,而且负权限导致的全局关联也降低了权限系统的稳定性。我更倾向于将group作为权限设置时的一种辅助标记手段,系统中只记录用户最终拥有的角色,即相当于记录用户通过group拥有权限的推导完成的结果, 如果需要权限细调,我们直接在用户拥有的角色列表上直接进行。当然,如果实现的复杂一些,权限系统对外暴露的接口仍然可以模拟为能够指定userGroup的权限。
推理在面向对象语言中最明显的表现是继承,所以有些人将subject域中的推理直接等价于role之间的继承问题,这未必是最好的选择。继承可以形成非常复杂的推理关系,但是可能过于复杂了(特别是直接使用sql语句无法实现树形推理查询)。按照级列理论,从不相关发展到下一阶段是出现简单的序关系,即我们可以说subject出现级别上的差异,高级别subject将自动具有低级别的权限。一种选择是定义roleRank,规定高级别role自动具有低级别role的权限,但考虑到user与role的两分结构,我们也可以同时定义userRank和roleRank,规定高级别user自动具有低级别的role,而role之间不具有推理关系。在面向对象领域中,我们已经证实了完全采用继承来组织对象关系会导致系统的不稳定,所以我倾向于第二种选择,即将role看作某种类似于interface的东西,一种权限的切片。为了进一步限制这种推导关系,我们可以定义所谓的安全域的概念. security domain, 规定推导只能在一定的域中才能进行。
select user.userId, role.roleId
from user, role
where user.userRank > role.roleRank
and user.domain = role.domain

将权限控制一般需要施加在最细的粒度上,这在复杂的系统中可能过于理想化了。复杂的情况下我们需要进行局部化设计,即进行某些敏感操作之前进行一系列复杂的权限校验工作。当完成这些工作之后,进入某个security zone, 在其中进行操作就不再需要校验了。
总的来说,权限系统采用非常复杂的结构效果未必理想。很多时候只是个管理模式的问题,应该尽量通过重新设计权限空间的结构来加以规避。不过在一些非常复杂的权限控制环境下,也许简单的描述信息确实很难有效的表达权限策略(虽然我从未遇到过),此时尝试一下规则引擎可能比在权限系统中强行塞入越来越多的约束要好的多

 


权限系统(4)--resource

 

权限管理中进行数据访问控制,其基本模式如下
operation target = selector(resource)
selector = user selector + auth filter
这里需要对resource的结构,以及选择算子的显式建模。selector必须允许权限系统追加filter,例如
IDataSource包中所使用的Query对象。
sql语言的表达能力有限, 作为选择算子来使用有时需要resource作一些结构上的调整,增加一些冗余的字段。例如表达一段时间内的利率,我们需要使用from_date和to_date两个字段来进行描述,其中to_date的值与下一条记录的from_date相同。
value from_date to_date
0.01 2003-01-01 2003-05-01
0.012 2003-05-01 2004-01-01

如果表达一条航线中的多个阶段,我们可能会在每条记录中增加起始站和终点站两个字段。
更重要的一个常见需求是树形结构在关系数据库中的表达。为了能够直接操纵一个分支下的所有记录,在层次固定的情况下,我们可能会增加多个分类字段,例如数据仓库中的层次维度。在层次数目不确定的情况下,我们将不得不使用层次码或者类似于url的其他方案,通过layer_code like '01.01.%' 之类的语句实现分支选择。为了限制选择的深度,我们可能还需要layer_level字段。基于层次码和层次数,我们可以建立多种选择算子,例如包含所有直接子节点,包含自身及所有父节点等等

权限系统(5)--动态性

 

动态权限最简单的一个表现是时限性,subject只在某个时间段内具有某种权限。这只需要在user和role的映射中,或者role自身的属性中增加startTime和expireTime即可。

更复杂的动态性一般与流程控制相关,此时权限控制应该由工作流系统完成,而不是在数据上增加越来越多的权限标记。在witrix平台中,使用tpl模板技术来定制权限设置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值