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

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

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

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

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

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

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


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

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,这意味着许可检查是成功的,允许用户运行任何想要做许可检查的动作。

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

rule CanDoAnythingToCustomersIfYouAreAnAdmin
when
  c: PermissionCheck(target 
== "customer")
  Role(name 
== "admin")
then
  c.grant();
end;
这个规则允许具有admin角色的用户执行任何customer许可检查的任何动作。         
posted @ 2009-09-16 12:21  行者吴江  阅读(1511)  评论(0编辑  收藏  举报