`

Seam 2.1中的安全升级 (二)

    博客分类:
  • Seam
阅读更多
Permission Management

尽管 Identity Management 提供了一致的API来管理用户帐户,我们依然需要一个方式来管理用户许可(Permission)。从前一个版本以来,在Seam 2.1.0中的验证特性经过了整个的修订。在以前开发者需要继承一个内建的 Identity 组件来实现自定义的许可(Permission)检查,在Seam 2.1.0中提供了一个可插拔的系统,可以让你注册你自己的许可(Permission)分析器而不用继承其他的组件了。下图展示了这些东西是如何协作的:






在上图中, Identity 现在使用 PermissionMapper 映射一个特别的ResolverChain来执行许可(Permission)检查,该ResolverChain可以配置一个或多个PermissionResolvers。Seam提供了 RuleBasedPermissionResolver (for resolving rule-based permission checks) 和 PersistentPermissionResolver (for performing checks based on permissions stored in persistent storage, such as a database)。如果你的程序需要自定义安全管理,实现你自己的PermissionResolver 也是相当简单的。

我想在进一步前进之前,我们需要定义下许可(Permission)是什么。在Seam中,许可(Permission)有3个方面:

    * A target, 一个在某些方面起作用的对象
    * An action, 在 target 上被执行的动作
    * A recipient, 具有在target上执行特定action的许可(Permission)的用户或则角色实体
   
   


   
许可(Permission)检查的target就是PermissionMapper用来判断使用那个ResolverChain来执行检查。这样可以实现为不同的对象配置不同的PermissionResolvers。例如:你可能希望仅仅使用RuleBasedPermissionResolver来执行Customer对象的许可(Permission)检查,同时使用PersistentPermissionResolver来执行Invoice对象上的许可(Permission)检查。PermissionMapper支持这种灵活性。
让我们实际的看看这些应用。


Persistent Permissions

SeamSpace示例允许用户上传一个图片。其他用户在浏览用户信息的时候可以看到该图片:







现在我们假设一些图片你想设置为私有的,而其他一些图片你想仅仅显示给你的朋友。点击你图片下的 padlock 图标,会打开图片的许可(Permission)管理页面:




在这个页面,我们可以看到那些用户和角色有查看这个图片的许可。在这个示例中,仅仅我的朋友具有查看该图片的权限。现在我想让该站点的任何用户都可以看到该图片。可以点击'new permission'来授权,会打开许可详细信息页面:





在这里我们通过选择角色或则具体的用户来提供特殊的许可权限。我希望所有的用户都可以查看,所以我从角色列表中选择‘user’,然后点击‘view’ checkbox。点击save按钮保存设置,然后返回到许可管理界面,在这里可以看到我设置的新许可:





当我们授予一个新的许可的时候,实际发生了什么呢?我们看看在这个场景后面使用的组件,ImagePermission. 下面是相关的代码:

@Name("imagePermission")
@Scope(CONVERSATION)
public class ImagePermission implements Serializable
{
   // (snip)
   @In PermissionManager permissionManager;
   @In PermissionSearch permissionSearch;

   private MemberImage target;  
   private Principal recipient;

   @SuppressWarnings("unchecked")
   @Begin(nested = true)
   public void createPermission() {
      target = (MemberImage) permissionSearch.getTarget();    
      // (snip)
   }

   public void applyPermissions() {
      // (snip)
  
      List<Permission> permissions = new ArrayList<Permission>();
    
      for (String role : selectedRoles)
      {
         Principal r = new Role(role);
         for (String action : selectedActions)
         {          
            permissions.add(new Permission(target, action, r));
         }
      }
     
      for (Member friend : selectedFriends)
      {
         MemberAccount acct = (MemberAccount) entityManager.createQuery(
               "select a from MemberAccount a where a.member = :member")
               .setParameter("member", friend)
               .getSingleResult();
       
         Principal p = new SimplePrincipal(acct.getUsername());
       
         for (String action : selectedActions)
         {
            permissions.add(new Permission(target, action, p));
         }
      }
     
      permissionManager.grantPermissions(permissions);

      Conversation.instance().endBeforeRedirect();
   }

   // (snip)
}

从上面的代码中我们可以看到 ImagePermission 是一个会话作用域(conversation-scoped)的组件。其实,它的功能被实现为一个嵌套的作用域,在同一个target对象上可以同时打开多个 'new permission' 窗口来操作。我们还可以看到PermissionManager通过@In 注解注入进来了。


现在 createPermission() 方法开始一个嵌套的会话 (thanks to the @Begin(nested = true) annotation),然后在我们的target对象中保存一个引用。当用户点击save按钮,在分配了指定的许可后,用来构建一些Permission对象来执行授权的applyPermissions()方法被调用了。在该函数内,使用一些授权的许可来调用PermissionManager.grant()。我们发些时间来详细解释下这个 PermissionManager (the heart of the Permission Management API)。


The PermissionManager Component

就像 IdentityManager 用来处理用户和角色操作一样,PermissionManager 被设计为来操作许可。它提供了API来允许授权和激活许可,或则一个target对象的列表。我们来看看一些方法:

    * listPermissions(String target, String action)
    * listPermissions(Object target)
    * grantPermission(Permission permission)
    * grantPermissions(List<Permission> permissions)
    * revokePermission(Permission permission)
    * revokePermissions(List<Permission> permissions)

就像 IdentityManager 需要一个 IdentityStore 来保存数据, PermissionManager 也需要一个 PermissionStore 来和持久化存储打交到。Seam 只提供了一个 PermissionStore 实现 - JpaPermissionStore, 可以通过JPA来和数据库存在互操作。在理论上也可以把许可信息保存在LDAP目录中,或则一个普通文件中,但是大多数情况下还是保存在一个数据库中的。

现在来看看SeamSapce示例中 AccountPermission entity bean的代码,下面的代码为了排版被截断了:


@Entity
public class AccountPermission implements Serializable
{
   // snip field declarations, etc
    
   @PermissionUser @PermissionRole
   public String getRecipient() { return recipient; }
   public void setRecipient(String recipient) { this.recipient = recipient; }

   @PermissionTarget public String getTarget() { return target; }
   public void setTarget(String target) { this.target = target; }

   @PermissionAction
   public String getAction() { return action; }
   public void setAction(String action) { this.action = action; }

   @PermissionDiscriminator
   public String getDiscriminator() { return discriminator; }
   public void setDiscriminator(String discriminator) { this.discriminator = discriminator; }
}

再一次的,我们注意到使用了一些特殊的注解。这里我告诉你,许可既可以指定到用户上也可以指定到角色上。这就意味着可以把许可信息保存的分开的表格中,这从性能角度来说,把他们保存在单个表中,使用一个辨别器列(discriminator column)来区分他们,可能看起来更合适。因此在上面的代码中,我们看到getDiscriminator() 使用了@PermissionDiscriminator注解,表明该列用来判断许可是应用到用户上还是角色上。

继续向下看,用来配置一个保存许可信息的实体注解如下:

    * @PermissionUser - designates the field that contains the name of the recipient of the permission (for user-assigned permissions)
    * @PermissionRole - same as above, but for role-assigned permissions
    * @PermissionTarget - contains a unique identifier string, identifying a single instance of an object. Alternatively, can contain a class name or any arbitrary string for the designation of more generalised permissions.
    * @PermissionAction - contains a list of the actions that the recipient may perform on the target object.
    * @PermissionDiscriminator - see paragraph above


这里说明下 - permission management 特性只用来管理持久的许可信息( persistent permissions)。当然在大多数情况下,你可能希望通过业务逻辑来应用许可权限,例如:用户应该具有查看和管理他们自己图片的权限。这类许可有Seam的rule-based security(基于角色的安全)来处理,在下面我们来详细讨论下这个问题。


Rule-based Permissions


Seam 基于Drools 提供了一个rule-based security模型,因此这并不是一个真正的新功能。我们这里来重新温习下这是如何应用到我们的示例项目SeamSpace中的。

继续图片安全这个话题,当处理用户图片的时候,除了我们上面讨论的问题外,显然我们需要一些基础的安全规则。在默认的情况下,查看用户的图片被安全规则限制了,这意味着在SeamSpace中,如果你想看一个用户的图片,你必须在被该用户授权后才可以查看(either via a persistent permission grant, or a security rule)。另外请记住,我们特别的需要允许下面的一些事情:

    * Users should be allowed to grant and revoke permissions for their own images
    * Users should be allowed to delete their own images
    * User profile images (a user's main image, i.e. their 'avatar') should always be viewable by anyone
    * Users should always be allowed to view their own images (of course)
    * User images with 'friend' permissions should be viewable by the user's friends (more on this in a bit)

现在我们详细的看看这些规则。首先,用户应该允许给他们的图片授予和撤回许可权限。这是相当直接的,并且作为两个独立的规则实现了。当和对象许可一起使用的时候,Seam会插入一个PermissionCheck对象到Drools的工作内存(working memory)中,该内存包含许可目标和根据用户要做什么分别由'seam.grant-permission' 或则 'seam.revoke-permission'(based on whether PermissionManager.grantPermission() or PermissionManager.revokePermission() is called)定义的一个动作(containing both the target of the permission, and an action either being 'seam.grant-permission' or 'seam.revoke-permission' depending on what the user is trying to do (based on whether PermissionManager.grantPermission() or PermissionManager.revokePermission() is called))。用于验证用户的MemberAccount示例一直在working memory中,在实际上下面的规则是: '如果我们正在处理的MemberImage是属于当前登陆的用户的,那么就授予许可权限(if the MemberImage for which we're performing the permission check is owned by the current user, then grant the permission)':

rule GrantImagePermissions
    no-loop
    activation-group "permissions"
when
    acct: MemberAccount()
    image: MemberImage(mbr : member -> (mbr.memberId.equals(acct.member.memberId)))
    check: PermissionCheck(target == image, action == "seam.grant-permission", granted == false)
then
    check.grant();
end

rule RevokeImagePermissions
    no-loop
    activation-group "permissions"
when
    acct: MemberAccount()
    image: MemberImage(mbr : member -> (mbr.memberId.equals(acct.member.memberId)))
    check: PermissionCheck(target == image, action == "seam.revoke-permission", granted == false)
then
    check.grant();
end

在下一步,我们也需要一个允许用户删除他们自己图片的规则。和第一个规则相似,我们验证当前执行删除的图片是否属性该用户的,如果是那么就授予权限:

rule DeleteImage
    no-loop
    activation-group "permissions"
when
    acct: MemberAccount()
    image: MemberImage(mbr : member -> (mbr.memberId.equals(acct.member.memberId)))
    check: PermissionCheck(target == image, action == "delete", granted == false)
then
    check.grant();
end

用于查看用户图片的规则有点不同。这里我们简单的测试 -- 正在查看的图片是用户自己的图片(Here we simply test that the image being viewed is the profile image for the owning member) (i.e. image.getMember().getPicture() == image):

rule ViewProfileImage
    no-loop
    activation-group "permissions"
when
    image: MemberImage()
    check: PermissionCheck(target == image, action == "view", granted == false)
    eval( image.getMember().getPicture() == image )
then
    check.grant();
end

还有,用户应该总是可以查看他们自己的图片。这个权限验证类似于第一个规则,在那里我们简单的验证图片的所有者是否为当前登陆的用户:

rule ViewMyImages
    no-loop
    activation-group "permissions"
when
    acct: MemberAccount()
    image: MemberImage(mbr : member -> (mbr.memberId.equals(acct.member.memberId)))
    check: PermissionCheck(target == image, action == "view")
then
    check.grant();
end
Conditional Roles

最后,为了当我们的朋友查看我们的图片,我们需要定义一个特殊的规则。在前面我们看到了如何给‘friends’角色授权,然而根据上下文的不同‘riend’可能具有不同的意思。可以认为,在系统中的任何一个用户都是某人的‘friend’,你们当其他人来看图片的时候我们如何定义他们是否是一个‘friend’呢?这就是条件角色(conditional roles )的领域了,这些角色是特殊的,并且不能直接的授予给用户。

当一个对象的权限检查通过安全(security)API检查过后, permission manager就通知 security API一个conditional role被授予权限了,需要执行一个特殊的基础规则(rule-based)来验证该用户是否具有该角色,但在仅仅在permission check的上下文中执行。要实现这个功能,和往常一样把一个PermissionCheck对象插入到包含target和action的working memory中,然而也会附加的插入一个RoleCheck对象,该对象包含用来对比的conditional role的名字。这样我们可以写一个安全规则来验证是否授予conditional role权限:

rule FriendViewImage
    no-loop
    activation-group "permissions"
when
    acct: MemberAccount()
    image: MemberImage(mbr : member -> (mbr.isFriend(acct.member)))
    PermissionCheck(target == image, action == "view")
    role: RoleCheck(name == "friends")
then
    role.grant();
end

这个规则检查当前验证的用户是否在图片所有者的朋友列表中。如果在的话,角色就暂时的授予这个许可检查。在某些复杂安全规则的情况下这具有非常大的灵活性( This allows great flexibility in assigning complex security rules to dynamic groups of users (in this case, a user's friends list) that don't necessarily warrant having their own role/group, due to either impracticality or design restrictions).


Strongly-typed Security Annotations

最后,作为结束我们来看看一些新的安全注解。为了使Seam Security看起来更'Web Beansy',我们引入了一些用于现在组件方法的类型安全的注解。通过使用meta-annotations,我们可以提供一些安全注解来应用安全限制到函数上或则参数上。Seam提供了一些开箱即用的注解,他们是标准的CRUD注解 (@Insert, @Read, @Update, @Delete) ,并且添加你自己的注解也是非常简单的。看看下面的例子:

@Begin @Insert(Customer.class)
public void createCustomer() {

这个注解的功能是,除非你具有插入新customer对象的权利,放置你不能调用createCustomer方法。类似的,我们可以注解一个方法的参数:

public void updateCustomer(@Update Customer customer) {

创建自己的注解只需要使用@PermissionCheck就可以了。来看个示例,你希望创建一个新的‘Promote’许可。该注解可以非常简单的实现,如下:

@Target({METHOD, PARAMETER})
@Documented
@Retention(RUNTIME)
@Inherited
@PermissionCheck
public @interface Promote {
     Class value() default void.class;
}

定义后,就可以直接使用了:

public void promoteStaff(@Promote Staff person) {

如果写一个基于规则的许可,该规则看起来就像这样:

rule PromoteStaffMember
    no-loop
    activation-group "permissions"
when
    acct: MemberAccount()
    Role(name == 'admin')
    staff: Staff()
    check: PermissionCheck(target == staff, action == "promote")
then
    check.grant();
end

许可动作(permission action)变为注解的小些名称了。这真的是很简单的!

同时我们仍然支持遗留的用于基于表达式的安全检查的@Restrict注解,我建议各位都使用新的类型安全的注解,至少在编译期安全检查就提供了简单的验证。


Conclusion

到这里就结束了JBoss Seam中的新安全特性。这里是一些参考的链接:

JBoss Seam Community Site (downloads, documentation, forums) - http://www.seamframework.org/

JBoss Seam 中文社区站点(下载,文档,论坛) - http://www.seamframework.cn/

JBoss Home Page - http://www.jboss.org
分享到:
评论

相关推荐

    seam2.1说明文档

    在 Seam 2.1 中,最显著的变化之一就是增强了安全性方面的功能,尤其是在用户权限验证机制上。这一版本不仅提供了更为精细的权限控制选项,还增加了对最新安全标准的支持,如更严格的密码策略和会话管理机制等。 ##...

    seam 2.1 参考手册

    - **RESTeasy集成**:RESTeasy是由JBoss成员Bill Burke开发的一个REST实现,它也被集成到Seam 2.1中,进一步增强了框架对RESTful应用的支持。 - **RESTful应用示例**:通过集成JAX-RS和RESTeasy,Seam 2.1能够提供更...

    Seam 2.1 安全模块框架

    Seam 2.1 安全模块框架是一个强大的工具,为使用 Seam 开发的应用程序提供了全面的安全管理和认证机制。框架的核心特性包括: 1. **安全验证**:Seam 提供了一个可扩展的安全验证层,基于 Java Authentication and ...

    基于Seam2.1的最新力作《Seam Framework: Experience the Evolution of Java EE, 2nd Edition》全书

    ### 基于Seam2.1的最新力作《Seam Framework: Experience the Evolution of Java EE, 2nd Edition》全书知识点概览 #### 一、Seam框架简介 Seam框架是JBoss组织推出的一个开源项目,旨在简化企业级应用开发,通过...

    jboss-seam2.1

    Seam为 应 业务业业 义 种统 组 你的 用程序中所有的 定 了一 一的 件模型。 Seam组件可能是 态义 关关 态 有状 的,包含与几个定 良好的上下文中任何一个相 的状 , 包括长开间运行上 下文、持久化上下文、业务流程...

    Jboss seam2.1版本开发参考文档

    ### JBoss Seam 2.1版本开发参考知识点 #### 一、JBoss Seam 框架简介 **JBoss Seam** 是一个企业级Java Web应用框架,它简化了基于Java平台的应用程序开发过程。该框架提供了强大的上下文管理功能、会话管理、...

    基于Seam2.1的最新力作《Seam Framework: Experience the Evolution of Java EE, 2nd Edition》摘要

    ### 基于Seam2.1的最新力作《Seam Framework: Experience the Evolution of Java EE, 2nd Edition》摘要分析 #### 核心概念:Seam框架概述 Seam框架是一款革命性的Web应用开发框架,它将标准的Java EE技术与一系列...

    jboss seam 2.0 中文手册

    整理自jboss seam 中文站,压缩为chm格式,便于广大jboss seam爱好者阅读,所有版权归jboss seam中文站所有。

    Seam Framework 2.0 Reference中文版

    #### 第二章:用 Seam-gen 起步 本章介绍了如何使用 Seam-gen 快速构建 Seam 应用程序。 - **准备活动**:准备开发环境,包括安装必要的软件和配置工具。 - **建立一个新的 Eclipse 项目**:使用 Eclipse 创建一个新...

    JBOSS SEAM组件中文手册

    **二、Seam核心概念** 1. **组件(Components)**: Seam的核心是组件模型,它允许开发者定义和管理应用中的对象。组件可以是简单的Java类,也可以是EJB或JSF Managed Beans。Seam自动管理组件的生命周期,包括创建、...

    SEAM 中文开发指南

    #### 二、SEAM 入门指南 ##### 1.1 尝试 SEAM - **环境搭建**: - 在 **JBoss AS** 上运行示例。 - 在 **Tomcat服务器** 上运行示例。 - 运行单元测试验证功能。 ##### 1.2 第一个例子:注册示例 - **代码...

    jboss seam 中文文档集合

    中文版的Seam_2.0_Reference_zh_CN.pdf为开发者提供了详细的框架功能和用法,覆盖了组件、事件处理、安全、国际化等各个方面,是学习和理解Seam不可或缺的资源。 **2. RichFaces** RichFaces 是一套基于JSF的组件...

    seam in action 中文 english

    6. **安全性**:Seam提供了内置的安全机制,如身份验证和授权,使得开发人员能够快速为应用添加安全特性。 7. **国际化与本地化**:Seam支持多语言环境,对于中英文双语版本的书籍,这为开发者提供了跨越语言障碍的...

    Seam security

    Seam Security是针对Java Web应用程序的安全框架,它是JBoss Seam项目的一部分,提供了全面的安全解决方案,包括...在日益增长的网络威胁环境中,采用像Seam Security这样的安全框架是确保Web应用程序安全的关键步骤。

    seam需要的jar包

    在这个“seam需要的jar包”压缩包中,包含了运行和开发Seam应用程序所需的各种库文件。 首先,Seam框架的核心依赖于JSF,这是Java EE中的一个用户界面组件框架,用于构建交互式Web应用。JSF提供了模型-视图-控制器...

    seam 2中文手册

    seam下一代web开发框架

    seam_in_action

    #### 2.1 第一部分:起步使用Seam - **第1章:Seam统一Java EE 3**:介绍 Seam 如何整合 Java EE 3 技术,形成统一的应用开发平台。 - **第2章:将Seam-Gentoo投入工作**:展示如何在 Gentoo Linux 系统上安装和配置...

    seam 中文文档 pdf

    seam 中文文档 pdf 格式 JSF+EJB3.0快速开发框架Seam的中文版向导。。。

Global site tag (gtag.js) - Google Analytics