Seam的安全框架-授权(Authorization)(译) (三)

为了解决应用程序权限。Seam安全提供了一个可扩展的框架。下面的类图显式了权限框架的主要组件的概览:

相关的类将在接下来的章节中进行详细的解释。

这实际是一个接口,它提供了解决个别对象权限的方法。Seam提供了下列内建的PermissionResolver实现,下面章节将详细描述它们:

  • RuleBasedPermissionResolver - 这个权限解析器使用Drools来解决基于规则的许可检查。

  • PersistentPermissionResolver - 这个权限解析器存储对象的权限在一个持久化存储器中,比如关系型数据库。

实现你自己的权限解析器是非常简单的。PermissionResolver接口只定义了两个必须实现的方法,如下表中显示的那样。在你的Seam项目中发布你自己的PermissionResolver,在部署期间会自己扫描到它并使用默认的ResolverChain注册。

表 15.7. PermissionResolver接口

返回类型

方法

说明

boolean

hasPermission(Object target, String action)

这个方法必须解决当前已验证用户(通过调用Identity.getPrincipal()获得)是否有通过targetaction参数指定的权限。如果用户有这个权限将返回true,反之,返回false

void

filterSetByAction(Set<Object> targets, String action)

这个方法将从指定的集合中移除任何对象,如果hasPermission()方法有同样的action参数值,将返回true


注意

由于他们是缓存在用户的会话,任何定制PermissionResolver实现必须遵守几个限制。第一,它们也许不包含任何比回话范围更细粒度的状态 (并且组件本身的范围应该是应用和回话)。第二,它们不能使用依赖注入,因为它们可能从多个线程同时访问。实际上从性能上考虑,推荐使用@BypassInterceptors注释来完全绕过Seam的拦截器栈。

一个ResolverChain包含一个有顺序的以解决对于一个特别对象类或者权限目标的对象权限的PermissionResolver的列表。

缺省的ResolverChain由在应用程序部署期间发现的所有权限解析器组成。当创建缺省的ResolverChain时,会触发org.jboss.seam.security.defaultResolverChainCreated事件(传递ResolverChain实例作为事件的参数)。它还允许添加额为的那些由于某些原因没有在发布期间发现的解析器,或者对重新对列表中的解析器进行排序和移除某个解析器。

下面这个序列图显示了权限框架中的组件之间在许可检查过程中的交互。一个许可检查可以源自好几个地方,例如:安全拦截器、s:hasPermissionEL函数、或者通过API调用Identity.checkPermission


  • 1. 启动一个许可检查某些地方(代码或通过一个EL表达式)导致调用Identity.hasPermission()

  • 1.1. Identity调用PermissionMapper.resolvePermission(),传递被解析的权限作为参数。

  • 1.1.1. PermissionMapper包含一个关于ResolverChain实例,以类为键值的Map。它使用这个映射来为权限的目标对象定位正确的ResolverChain。一旦它有一个正确的ResolverChain,它通过调用ResolverChain.getResolvers()取回PermissionResolver列表。

  • 1.1.2. 遍历ResolverChain中的PermissionResolverPermissionMapper调用它的hasPermission()方法,传递被检查的权限实例作为参数,然后成功的通过许可检查,PermissionMapper返回trueIdentity。如果PermissionResolver返回值没有true,许可检查失败。

Seam提供的内建权限解析器之一,RuleBasedPermissionResolver允许基于一套Drools安全规则来评估权限。使用规则引擎有以下这些优点 1)用来评估用户权限的业务逻辑的集中位置,2)快速──Drools使用非常有效的算法来评估大量的包括多条件的复杂规则。

如果使用Seam安全提供的基于规则的权限特性,随你项目需要发布以下Drools需要的jar包:

  • drools-compiler.jar

  • drools-core.jar

  • janino.jar

  • antlr-runtime.jar

  • mvel14.jar

RuleBasedPermissionResolver首先需要在components.xml中配置一个Drools规则库。缺省情况下,规则库名称为securityRules,如下示例:

< components  xmlns ="http://jboss.com/products/seam/components"
              xmlns:core
="http://jboss.com/products/seam/core"
              xmlns:security
="http://jboss.com/products/seam/security"
              xmlns:drools
="http://jboss.com/products/seam/drools"
              xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation
=
                  "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.1.xsd
                   http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd
                   http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.1.xsd"

                   http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.1.xsd"
>   

     
< drools:rule-base  name ="securityRules" >
         
< drools:rule-files >
             
< value > /META-INF/security.drl </ value >
         
</ drools:rule-files >
     
</ drools:rule-base >   

</ components >

缺省的规则库名称可以通过指定RuleBasedPermissionResolversecurity-rules属性来重载:

   < security:rule-based-permission-resolver  security-rules ="#{prodSecurityRules}" />

一旦配置好规则库(RuleBase)组件,就可以开始编写安全规则了。

编写安全规则的第一步是在你应用程序的jar文件的/META-INF目录的创建一个新的规则文件。通常这个文件像security.drl这样命名,然而你也可以用任何你喜欢的名字命名只要在components.xml中有对应的配置。

安全规则文件应该包含些什么呢?这时至少浏览一下Drools文档是个不错的注意,不管怎样,先从一个极简单的例子开始:

package  MyApplicationPermissions;
  
  
import  org.jboss.seam.security.permission.PermissionCheck;
  
import  org.jboss.seam.security.Role;
  
  rule CanUserDeleteCustomers
  when
    c: PermissionCheck(target 
==   " customer " , action  ==   " delete " )
    Role(name 
==   " admin " )
  then
    c.grant();
  end

让我们一步一步来看。我们首先看到的是包声明。在Drools中包本质上是一个规则的集合。这个包名你可以任意取──它不涉及规则基范围之外的任何东西。

接下来,我们注意到一些PermissionCheckRole类的导入语句。这些导入信息告诉规则引擎在我们的规则中将引用这些类。

最后,我完成规则的代码。每一个在包内的规则应该取一个唯一的名字(通常是规则目的的描述)。在这个例子中,我们的规则叫做CanUserDeleteCustomers,它用来检查一个用户是否允许删除一个客户记录。

从规则定义的主体来看,我们可以看到到两个截然不同的部分。规则有称之为左手边(LHS)和右手边(RHS)两部分。LHS由规则的条件部分组成,如:一列必须满足才能激活规则的条件。LHS用when表现。RHS是结果,或者只有满足LHS中的所有条件才能机会的规则中的动作部分。RHS用then表现。规则结尾用end表示。

如果我们看规则的LHS部分,能看到列出了两个条件。我们先看看第一个条件:

c: PermissionCheck(target  ==   " customer " , action  ==   " delete " )

这个条件标明工作内存中必须存在一个target属性等于“customer”,并且action属性等于“delete”的PermissionCheck对象。

那么,什么是工作内存(working memory)?在Drools的术语中也称为“有状态会话(stateful session)”,工作内存是一个保存上下文信息会话范围对象,那些上下文信息是规则引擎做出许可检查的决定时必须的。每次hasPermission()方法被调用,一个临时的PermissionCheck对象,或者Fact,被插入工作内存。PermissionCheck和要被检查的权限完全一致,因此如果你调用hasPermission("account", "create")那么在许可检查期间一个target等于“account”,action等于“create”的PermissionCheck对象将被插入工作内存。

除了PermissionCheck facts,也有一个为验证用户是其中成员之一的每一个角色的org.jboss.seam.security.Role fact。这些Role facts是和在每一次许可检查开始使的用户的已验证角色同步的。结果是,如果一个已验证用户不是角色的成员之一,任何在许可检查期间插入工作内存的Role对象都将在下一次许可检查发生前删除。除了PermissionCheckRole facts,工作内存也保存了验证过程产生的java.security.Principal对象。

通过调用RuleBasedPermissionResolver.instance().getSecurityContext().insert()方法,传递一个对象作为参数,还可以把这个对象作为一个额外的长期的fact插入到工作内存中。对于已讨论过得在每次许可检查开始时同步的Role对象是个例外。

回到我们简单例子中,我们会注意到LHS的第一行有一个c:前缀。这是一个变量绑定,用来引用匹配条件(本例中是PermissionCheck)后返回的对象。再看LHS的第二行,我们看见:

Role(name  ==   " admin " )

这个条件简单的说明工作内存中必须存在一个名为“admin”的Role对象。前面已经提到,用户角色在每一次许可检查的开始被插入工作内存。因此,这俩个条件本质上在说“如果你正在检查customer:delete权限并且用户是”admin“角色的成员之一,将激活规则”。

那么激活规则的结果是什么呢?让我们看看规则的RHS:

c.grant()

RHS由Java代码组成,在本例中调用了c对象的grant()方法,c对象已经在为PermissionCheck对象的变量绑定中提到了。除了PermissionCheck对象的nameaction属性,还有一个granted属性被初始化为false。调用PermissionCheckgrant()方法设置granted属性为true,这意味着许可检查是成功的,允许用户运行任何想要做许可检查的动作。

到目前为止,我们仅仅看了对字符串权限目标的检查。为更复杂类型的权限目标写安全规则当然也是可以的。比如,假设你希望写一个安全规则来允许你的用户创建blog评论。下面的规则演示了如何表达在需要MemberBlog的实例作为许可检查的目标,并且需要当前已验证用户是user角色的成员之一情况下的规则写法:

rule CanCreateBlogComment
  no
- loop
  activation
- group  " permissions "
when
  blog: MemberBlog()
  check: PermissionCheck(target 
==  blog, action  ==   " create " , granted  ==   false )
  Role(name 
==   " user " )
then
  check.grant();
end

通过子你的规则中忽略PermissionCheckaction限制, 实现一个通配符许可检查(允许针对一个给定的许可目标的所有动作)也是可能的。像这样:

rule CanDoAnythingToCustomersIfYouAreAnAdmin
when
  c: PermissionCheck(target 
==   " customer " )
  Role(name 
==   " admin " )
then
  c.grant();
end;
这个规则允许具有admin角色的用户执行任何customer许可检查的任何动作。         

转载于:https://www.cnblogs.com/rgbw/archive/2009/09/16/1567656.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值