使用 Acegi 保护 Java 应用程序,第 1 部分: 架构概览和安全过滤器

使用 Acegi Security System 实现基于 URL 的安全性

这份共分三部分的系列文章介绍了 Acegi 安全系统(Acegi Security System),它是用于 Java™ 企业应用程序的强大的开源安全框架。在第一篇文章中,Bilal Siddiqui 顾问将向您介绍 Acegi 的架构和组件,并展示如何使用它来保护一个简单的 Java 企业应用程序。

Bilal Siddiqui (xml4java@yahoo.co.uk), 自由顾问, WaxSys

Bilal Siddiqui 是一名电子工程师、XML 顾问,他还是 WaxSys(主要从事电子商务简化)的创建者之一。自从 1995 年毕业于拉合尔工程技术大学(University of Engineering and Technology,Lahore)电子工程专业以后,他就开始为工业控制系统设计各种软件解决方案。稍后,他致力于 XML 方面并使用他在 C++ 编程中取得的经验来构建基于 Web 和 WAP 的 XML 处理工具、服务器端解析方案和服务应用程序。Bilal 是一名技术推广者,并且是一名多产的技术作家。



2007 年 5 月 08 日

Acegi Security System 是一种功能强大并易于使用的替代性方案,使您不必再为 Java 企业应用程序编写大量的安全代码。虽然它专门针对使用 Spring 框架编写的应用程序,但是任何类型的 Java 应用程序都没有理由不去使用 Acegi。这份共分三部分的系列文章详细介绍了 Acegi,并展示了如何使用它保护简单的企业应用程序以及更复杂的应用程序。

本系列首先介绍企业应用程序中常见的安全问题,并说明 Acegi 如何解决这些问题。您将了解 Acegi 的架构模型及其安全过滤器,后者包含了在保护应用程序中将用到的大多数功能。您还将了解到各个过滤器如何单独进行工作,如何将它们组合起来,以及过滤器如何在一个企业安全实现中将各种功能从头到尾地链接起来。本文最后通过一个样例应用程序演示了基于 URL 安全系统的 Acegi 实现。本系列后续两篇文章将探究 Acegi 的一些更高级的应用,包括如何设计和托管访问控制策略,然后如何去配置 Acegi 以使用这些策略。

您必须 下载 Acegi,这样才能编译本文的示例代码并运行本文的样例应用程序。还必须有作为工作站的一部分运行的 Tomcat 服务器。

企业应用程序安全性

由于企业内容管理(ECM)应用程序管理存储在不同类型数据源(如文件系统、关系数据库和目录服务)中的企业内容的编写和处理,ECM 安全性要求对这些数据源的访问进行控制。比如,一个 ECM 应用程序可能会控制被授权读取、编辑或删除数据的对象,而这些数据和制造业企业的设计、市场营销、生产以及质量控制有关。

在一个 ECM 安全场景中,比较常见的就是通过对企业资源定位符(或网络地址)应用安全性,从而实现访问控制。这种简单的安全模型被称为统一资源定位符 或 URL 安全性。正如我在本文后面(以及本系列后续文章)所演示的一样,Acegi 为实现 URL 安全性提供了全面的特性。

然而,在很多企业场景中,URL 安全性还远远不够。比如,假设一个 PDF 文档包含某个制造业公司生产的特殊产品的数据。文档的一部分包含了将由该公司的设计部门编辑和更新的设计数据。另一部分包含了生产经理将使用的生产数据。对于诸如此类的场景,需要实现更加细粒度的安全性,对文档的不同部分应用不同的访问权限。

本文介绍了 Acegi 为实现 URL 安全性而提供的各种功能。本系列的下一篇文章将演示此框架的基于方法的安全性,它提供了对企业数据访问的更细粒度的控制。


Acegi Security System

Acegi Security System 使用安全过滤器来提供企业应用程序的身份验证和授权服务。该框架提供了不同类型的过滤器,可以根据应用程序的需求进行配置。您将在本文后面了解到 安全过滤器的不同类型;现在,只需注意可以为如下任务配置 Acegi 安全过滤器:

  1. 在访问一个安全资源之前提示用户登录。
  2. 通过检查安全标记(如密码),对用户进行身份验证。
  3. 检查经过身份验证的用户是否具有访问某个安全资源的特权。
  4. 将成功进行身份验证和授权的用户重定向到所请求的安全资源。
  5. 对不具备访问安全资源特权的用户显示 Access Denied 页面。
  6. 在服务器上记录成功进行身份验证的用户,并在用户的客户机上设置安全 cookie。使用该 cookie 执行下一次身份验证,而无需要求用户登录。
  7. 将身份验证信息存储在服务器端的会话对象中,从而安全地进行对资源的后续请求。
  8. 在服务器端对象中构建并保存安全信息的缓存,从而优化性能。
  9. 当用户退出时,删除为用户安全会话而保存的服务器端对象。
  10. 与大量后端数据存储服务(如目录服务或关系数据库)进行通信,这些服务用于存储用户的安全信息和 ECM 的访问控制策略。

正如这个列表显示的那样,Acegi 的安全过滤器允许您执行保护企业应用程序所需的几乎任何事情。


架构和组件

对 Acegi 了解越多,使用起来就越简单。这一节介绍 Acegi 的组件;接下来您将了解该框架如何使用反转控制(IOC)和 XML 配置文件来组合组件并表示它们的依赖关系。

四大组件

Acegi Security System 由四种主要类型的组件组成:过滤器、管理器、提供者和处理程序。

过滤器
这种最高级的组件提供了常见的安全服务,如身份验证、会话处理以及注销。我将在 本文后面的部分 深入讨论过滤器。
管理器
过滤器仅是安全相关功能的高级抽象:实际上要使用管理器和提供者实现身份验证处理和注销服务。管理器管理由不同提供者提供的较低级的安全服务。
提供者
有大量的提供者可用于和不同类型的数据存储服务通信,例如目录服务、关系数据库或简单的内存中的对象。这意味着您可以将用户库和访问控制协议存储在任何一种这样的数据存储服务中,并且 Acegi 的管理器将在运行时选择合适的提供者。
处理程序
有时任务可能会被分解为多个步骤,其中每个步骤由一个特定的处理程序执行。比方说,Acegi 的 注销过滤器 使用两个处理程序来退出一个 HTTP 客户机。其中一个处理程序使用户的 HTTP 会话无效,而另一个处理程序则删除用户的 cookie。当根据应用程序需求配置 Acegi 时,多个处理程序能够提供很好的灵活性。您可以使用自己选择的处理程序来执行保护应用程序所需的步骤。

反转控制

Acegi 的组件通过彼此之间的依赖来对企业应用程序进行保护。比如,一个身份验证处理过滤器需要一个身份验证管理器选择一个合适的身份验证提供者。这就是说您必须能够表示和管理 Acegi 组件的依赖关系。

IOC 实现通常用于管理 Java 组件之间的依赖关系。IOC 提供了两个重要的特性:

  1. 它提供了一种语法,表示应用程序所需的组件以及这些组件如何相互依赖。
  2. 它保证了所需的组件在运行时是可用的。

XML 配置文件

Acegi 使用 Spring 框架(请参见 参考资料)附带的流行开源 IOC 实现来管理其组件。Spring 需要您编写一个 XML 配置文件来表示组件的依赖关系,如清单 1 所示:

清单 1. Spring 配置文件的结构
<beans>
    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value> value here </value>
        </property>
    </bean>

    <bean id="authenticationProcessingFilter"
        class="org.acegisecurity.ui.webapp.AuthenticationProcessingFitler">
        <property name="authenticationManager" ref="authManager"/>
        <!-- Other properties -->
    </bean>

    <bean id="authManager"
        class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <!--  List of providers here -->
        </property>
    </bean>
    <!-- Other bean tags -->
</beans>

如您所见,Acegi 使用的 Spring XML 配置文件包含一个 <beans> 标记,它封装了一些其他的 <bean> 标记。所有的 Acegi 组件(即过滤器、管理器、提供者等)实际上都是 JavaBean。XML 配置文件中的每个 <bean> 标记都代表一个 Acegi 组件。

进一步解释 XML 配置文件

首先将注意到的是每个 <bean> 标记都包含一个 class 属性,这个属性标识组件所使用的类。<bean> 标记还具有一个 id 属性,它标识作为 Acegi 组件工作的实例(Java 对象)。

比方说,清单 1 的第一个 <bean> 标记标识了名为 filterChainProxy 的组件实例,它是名为 org.acegisecurity.util.FilterChainProxy 的类的实例。

使用 <bean> 标记的子标记来表示 bean 的依赖关系。比如,注意第一个 <bean> 标记的 <property> 子标记。<property> 子标记定义了 <bean> 标记依赖的其他 bean 或值。

所以在 清单 1 中,第一个 <bean> 标记的 <property> 子标记具有一个 name 属性和一个 <value> 子标记,分别定义了这个 bean 依赖的属性的名称和值。

同样,清单 1 中的第二个和第三个 <bean> 标记定义了一个过滤器 bean 依赖于一个管理器 bean。第二个 <bean> 标记表示过滤器 bean,而第三个 <bean> 标记表示管理器 bean。

过滤器的 <bean> 标记包含一个 <property> 子标记,该子标记具有两个属性:namerefname 属性定义了过滤器 bean 的属性,而 ref 属性引用了管理器 bean 的实例(名称)。

下一节将展示如何在 XML 配置文件中配置 Acegi 过滤器。在本文后面的内容中,您将在一个样例 Acegi 应用程序中使用过滤器。


安全过滤器

正如我前面提到的一样,Acegi 使用安全过滤器为企业应用程序提供身份验证和授权服务。您可以根据应用程序的需要使用和配置不同类型的过滤器。这一节将介绍五种最重要的 Acegi 安全过滤器。

Session Integration Filter

Acegi 的 Session Integration Filter(SIF)通常是您将要配置的第一个过滤器。SIF 创建了一个安全上下文对象,这是一个与安全相关的信息的占位符。其他 Acegi 过滤器将安全信息保存在安全上下文中,也会使用安全上下文中可用的安全信息。

SIF 创建安全上下文并调用过滤器链中的其他过滤器。然后其他过滤器检索安全上下文并对其进行更改。比如,Authentication Processing Filter(我将稍后进行介绍)将用户信息(如用户名、密码和电子邮件地址)存储在安全上下文中。

当所有的处理程序完成处理后,SIF 检查安全上下文是否更新。如果任何一个过滤器对安全上下文做出了更改,SIF 将把更改保存到服务器端的会话对象中。如果安全上下文中没有发现任何更改,那么 SIF 将删除它。

在 XML 配置文件中对 SIF 进行了配置,如清单 2 所示:

清单 2. 配置 SIF
<bean id="httpSessionContextIntegrationFilter"        
     class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>

Authentication Processing Filter

Acegi 使用 Authentication Processing Filter(APF)进行身份验证。APF 使用一个身份验证(或登录)表单,用户在其中输入用户名和密码,并触发身份验证。

APF 执行所有的后端身份验证处理任务,比如从客户机请求中提取用户名和密码,从后端用户库中读取用户参数,以及使用这些信息对用户进行身份验证。

在配置 APF 时,您必须提供如下参数:

  • Authentication manager 指定了用来管理身份验证提供者的身份验证管理器。
  • Filter processes URL 指定了客户在登录窗口中按下 Sign In 按钮时要访问的 URL。收到这个 URL 的请求后,Acegi 立即调用 APF。
  • Default target URL 指定了成功进行身份验证和授权后呈现给用户的页面。
  • Authentication failure URL 指定了身份验证失败情况下用户看到的页面。

APF 从用户的请求对象中得到用户名、密码和其他信息。它将这些信息传送给身份验证管理器。身份验证管理器使用适当的提供者从后端用户库中读取详细的用户信息(如用户名、密码、电子邮件地址和用户访问权利或特权),对用户进行身份验证,并将信息存储在一个 Authentication 对象中。

最后,APF 将 Authentication 对象保存在 SIF 之前创建的安全上下文中。存储在安全上下文中的 Authentication 对象将用于做出授权决策。

APF 的配置如清单 3 所示:

清单 3. 配置 APF
<bean id="authenticationProcessingFilter"
    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
    <property name="authenticationManager"
        ref="authenticationManager" />
    <property name="filterProcessesUrl"
        value="/j_acegi_security_check" />
    <property name="defaultTargetUrl"
        value="/protected/protected1.jsp" />
    <property name="authenticationFailureUrl"
        value="/login.jsp?login_error=1" />
</bean>

可以从这段代码中看到,APF 依赖于上面讨论的这四个参数。每个参数都是作为清单 3 所示的 <property> 标记配置的。

Logout Processing Filter

Acegi 使用一个 Logout Processing Filer(LPF)管理注销处理。当客户机发来注销请求时,将使用 LPF 进行处理。它标识了来自由客户机所调用 URL 的注销请求。

LPF 的配置如清单 4 所示:

清单 4. 配置 LPF
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
    <constructor-arg value="/logoutSuccess.jsp"/>
    <constructor-arg>
        <list>
            <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
        </list>
    </constructor-arg>
</bean>

可以看到 LPF 在其构造方法中包含两个参数:注销成功 URL(/logoutSuccess.jsp)和处理程序列表。注销成功 URL 用来在注销过程完成后重定向客户机。处理程序执行实际的注销过程;我在这里只配置了一个处理程序,因为只需一个处理程序就可以使 HTTP 会话变为无效。我将在本系列下一篇文章中讨论更多的处理程序。

Exception Translation Filter

Exception Translation Filter(ETF)处理身份验证和授权过程中的异常情况,比如授权失败。在这些异常情况中,ETF 将决定如何进行操作。

比如,如果一个没有进行身份验证的用户试图访问受保护的资源,ETF 将显示一个登录页面要求用户进行身份验证。类似地,在授权失败的情况下,可以配置 ETF 来呈现一个 Access Denied 页面。

ETF 的配置如清单 5 所示:

清单 5. 配置 ETF
<bean id="exceptionTranslationFilter"
    class="org.acegisecurity.ui.ExceptionTranslationFilter">
    <property name="authenticationEntryPoint">
        <bean 
            class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
            <property name="loginFormUrl" value="/login.jsp" />
        </bean>
    </property>
    <property name="accessDeniedHandler">
        <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
            <property name="errorPage" value="/accessDenied.jsp" />
        </bean>
    </property>
</bean>

正如清单 5 所示,ETF 包含两个参数,名为 authenticationEntryPointaccessDeniedHandlerauthenticationEntryPoint 属性指定登录页面,而 accessDeniedHandler 指定 Access Denied 页面。

拦截过滤器

Acegi 的拦截过滤器 用于做出授权决策。您需要在 APF 成功执行身份验证后对拦截过滤器进行配置,以使其发挥作用。拦截器使用应用程序的访问控制策略来做出授权决定。

本系列的下一篇文章将展示如何设计访问控制策略,如何将它们托管在目录服务中,以及如何配置 Acegi 以读取您的访问控制策略。但是,目前我将继续向您展示如何使用 Acegi 配置一个简单的访问控制策略。在本文后面的部分,您将看到使用简单的访问控制策略构建一个样例应用程序。

配置简单的访问控制策略可分为两个步骤:

  1. 编写访问控制策略。
  2. 根据策略配置 Acegi 的拦截过滤器。

步骤 1. 编写简单的访问控制策略

首先看一下 清单 6,它展示了如何定义一个用户及其用户角色:

清单 6. 为用户定义简单的访问控制策略
    alice=123,ROLE_HEAD_OF_ENGINEERING

清单 6 所示的访问控制策略定义了用户名 alice,它的密码是 123,角色是 ROLE_HEAD_OF_ENGINEERING。(下一节将说明如何在文件中定义任意数量的用户及其用户角色,然后配置拦截过滤器以使用这些文件。)

步骤 2. 配置 Acegi 的拦截过滤器

拦截过滤器使用三个组件来做出授权决策,我在清单 7 中对其进行了配置:

清单 7. 配置拦截过滤器
<bean id="filterInvocationInterceptor"
    class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="accessDecisionManager" ref="accessDecisionManager" />
    <property name="objectDefinitionSource">
        <value>
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
            PATTERN_TYPE_APACHE_ANT
            /protected/**=ROLE_HEAD_OF_ENGINEERING
            /**=IS_AUTHENTICATED_ANONYMOUSLY
        </value>
    </property>
    <!--  More properties of the interceptor filter -->
</bean>

如清单 7 所示,配置所需的三个组件是 authenticationManageraccessDecisionManagerobjectDefinitionSource

  • authenticationManager 组件与我在介绍 Authentication Processing Filter 时讨论过的身份验证管理器相同。拦截过滤器可以在授权的过程中使用 authenticationManager 重新对客户机进行身份验证。
  • accessDecisionManager 组件管理授权过程,这部分内容将在本系列的下篇文章中详细讨论。
  • objectDefinitionSource 组件包含对应于将要发生的授权的访问控制定义。例如,清单 7 中的 objectDefinitionSource 属性值包含两个 URL(/protected/*/*)。其值定义了这些 URL 的角色。/protected/* URL 的角色是 ROLE_HEAD_OF_ENGINEERING。您可以根据应用程序的需要定义任何角色。

    回想一下 清单 6,您为用户名 alice 定义了 ROLE_HEAD_OF_ENGINEERING。这就是说 alice 将能够访问 /protected/* URL。

过滤器工作原理

正如您已经了解到的一样,Acegi 的组件彼此依赖,从而对您的应用程序进行保护。在本文后面的部分,您将看到如何对 Acegi 进行配置,从而按照特定的顺序应用安全过滤器,因此需要创建过滤器链。出于这个目的,Acegi 保存了一个过滤器链对象,它封装了为保护应用程序而配置了的所有过滤器。图 1 展示了 Acegi 过滤器链的生命周期,该周期从客户机向您的应用程序发送 HTTP 请求开始。(图 1 显示了服务于浏览器客户机的容器。)

图 1. 托管 Acegi 过滤器链以安全地为浏览器客户机服务的容器
Acegi 过滤器的生命周期

下面的步骤描述了过滤器链的生命周期:

  1. 浏览器客户机向您的应用程序发送 HTTP 请求。
  2. 容器接收到 HTTP 请求并创建一个请求对象,该对象将封装 HTTP 请求中包含的信息。容器还创建一个各种过滤器都可处理的响应对象,从而为发出请求的客户机准备好 HTTP 响应。容器然后调用 Acegi 的过滤器链代理,这是一个代理过滤器。该代理知道应用的过滤器的实际顺序。当容器调用代理时,它将向代理发送请求、响应以及过滤器链对象。
  3. 代理过滤器调用过滤器链中第一个过滤器,向其发送请求、响应和过滤器链对象。
  4. 链中的过滤器逐个执行其处理。一个过滤器可以通过调用过滤器链中下一个过滤器随时终止自身处理。有的过滤器甚至根本不执行任何处理(比如,如果 APF 发现一个到来的请求没有要求身份验证,它可能会立即终止其处理)。
  5. 当身份验证过滤器完成其处理时,这些过滤器将把请求和响应对象发送到应用程序中配置的拦截过滤器。
  6. 拦截器决定是否对发出请求的客户机进行授权,使它访问所请求的资源。
  7. 拦截器将控制权传输给应用程序(比如,成功进行了身份验证和授权的客户机请求的 JSP 页面)。
  8. 应用程序改写响应对象的内容。
  9. 响应对象已经准备好了,容器将响应对象转换为 HTTP 响应,并将响应发送到发出请求的客户机。

为帮助您进一步理解 Acegi 过滤器,我将详细探讨其中两个过滤器的操作:Session Integration Filter 和 Authentication Processing Filter。

SIF 如何创建一个安全上下文

图 2 展示了 SIF 创建安全上下文所涉及到的步骤:

图 2. SIF 创建安全上下文
SIF 如何创建安全上下文

现在详细地考虑下面这些步骤:

  1. Acegi 的过滤器链代理调用 SIF 并向其发送请求、响应和过滤器链对象。注意:通常将 SIF 配置为过滤器链中第一个过滤器。
  2. SIF 检查它是否已经对这个 Web 请求进行过处理。如果是的话,它将不再进一步进行处理,并将控制权传输给过滤器链中的下一个过滤器(参见下面的第 4 个步骤)。如果 SIF 发现这是第一次对这个 Web 请求调用 SIF,它将设置一个标记,将在下一次使用该标记,以表示曾经调用过 SIF。
  3. SIF 将检查是否存在一个会话对象,以及它是否包含安全上下文。它从会话对象中检索安全上下文,并将其放置在名为 security context holder 的临时占位符中。如果不存在会话对象,SIF 将创建一个新的安全上下文,并将它放到 security context holder 中。注意:security context holder 位于应用程序的范围内,所以可以被其他的安全过滤器访问。
  4. SIF 调用过滤器链中的下一个过滤器。
  5. 其他过滤器可以编辑安全上下文。
  6. SIF 在过滤器链完成处理后接收控制权。
  7. SIF 检查其他的过滤器是否在其处理过程中更改了安全上下文(比如,APF 可能将用户详细信息存储在安全上下文中)。如果是的话,它将更新会话对象中的安全上下文。就是说在过滤器链处理过程中,对安全上下文的任何更改现在都保存在会话对象中。

APF 如何对用户进行身份验证

图 3 展示了 APF 对用户进行身份验证所涉及到的步骤:

图 3. APF 对用户进行身份验证
APF 如何对用户进行身份验证

现在仔细考虑以下这些步骤:

  1. 过滤器链中前面的过滤器向 APF 发送请求、响应和过滤链对象。
  2. APF 使用从请求对象中获得的用户名、密码以及其他信息创建身份验证标记。
  3. APF 将身份验证标记传递给身份验证管理器。
  4. 身份验证管理器可能包含一个或更多身份验证提供者。每个提供者恰好支持一种类型的身份验证。管理器检查哪一种提供者支持它从 APF 收到的身份验证标记。
  5. 身份验证管理器将身份验证标记发送到适合进行身份验证的提供者。
  6. 身份验证提供者支持从身份验证标记中提取用户名,并将它发送给名为 user cache service 的服务。Acegi 缓存了已经进行过身份验证的用户。该用户下次登录时,Acegi 可以从缓存中加载他或她的详细信息(比如用户名、密码和权限),而不是从后端数据存储中读取数据。这种方法使得性能得到了改善。
  7. user cache service 检查用户的详细信息是否存在于缓存中。
  8. user cache service 将用户的详细信息返回给身份验证提供者。如果缓存不包含用户详细信息,则返回 null。
  9. 身份验证提供者检查缓存服务返回的是用户的详细信息还是 null。
  10. 如果缓存返回 null,身份验证提供者将用户名(在步骤 6 中提取)发送给另一个名为 user details service 的服务。
  11. user details service 与包含用户详细信息的后端数据存储通信(如目录服务)。
  12. user details service 返回用户的详细信息,或者,如果找不到用户详细信息则抛出身份验证异常。
  13. 如果 user cache service 或者 user details service 返回有效的用户详细信息,身份验证提供者将使用 user cache service 或 user details service 返回的密码来匹配用户提供的安全标记(如密码)。如果找到一个匹配,身份验证提供者将用户的详细信息返回给身份验证管理器。否则的话,则抛出一个身份验证异常。
  14. 身份验证管理器将用户的详细信息返回给 APF。这样用户就成功地进行了身份验证。
  15. APF 将用户详细信息保存在 图 2 所示由步骤 3 创建的安全上下文中。
  16. APF 将控制权传输给过滤器链中的下一个过滤器。

一个简单的 Acegi 应用程序

在本文中,您已经了解了很多关于 Acegi 的知识,所以现在看一下利用您目前学到的知识能做些什么,从而结束本文。对于这个简单的演示,我设计了一个样例应用程序(参见 下载),并对 Acegi 进行了配置以保护它的一些资源。

样例应用程序包含 5 个 JSP 页面:index.jsp、protected1.jsp、protected2.jsp、login.jsp 和 accessDenied.jsp。

index.jsp 是应用程序的欢迎页面。它向用户显示了三个超链接,如图 4 所示:

图 4. 样例应用程序的欢迎页面:
一个简单的 Acegi 应用程序

图 4 所示的链接中,其中两个链接指向了被保护的资源(protected1.jsp 和 protected2.jsp),第三个链接指向登录页面(login.jsp)。只有在 Acegi 发现用户没有被授权访问受保护的资源时,才会显示 accessDenied.jsp 页面。

如果用户试图访问任何受保护的页面,样例应用程序将显示登录页面。当用户使用登录页面进入后,应用程序将自动重定向到被请求的受保护资源。

用户可以通过单击欢迎页面中的第三个链接直接请求登录页面。这种情况下,应用程序显示用户可以进入系统的登录页面。进入系统以后,应用程序将用户重定向到 protected1.jsp,它是用户进入系统而没有请求特定的受保护资源时显示的默认资源。

配置样例应用程序

为本文下载的源代码包含一个名为 acegi-config.xml 的 XML 配置文件,它包含 Acegi 过滤器的配置。根据 安全过滤器的讨论 中的示例,您应该很熟悉这些配置。

我还为样例应用程序编写了一个 web.xml 文件,如清单 8 所示:

清单 8. 样例应用程序的 web.xml 文件
<web-app>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/acegi-config.xml</param-value>
    </context-param>
    <filter>
        <filter-name>Acegi Filter Chain Proxy</filter-name>
        <filter-class>
            org.acegisecurity.util.FilterToBeanProxy
        </filter-class>
        <init-param>
            <param-name>targetClass</param-name>
            <param-value>
                org.acegisecurity.util.FilterChainProxy
            </param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>Acegi Filter Chain Proxy</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

web.xml 文件配置如下:

  • acegi-config.xml 文件的 URL 位于 <context-param> 标记中。
  • Acegi 过滤器链代理类的名称位于 <filter> 标记中。
  • URL 到 Acegi 过滤器链代理的映射在 <filter-mapping> 标记中。注意:您可以简单地将应用程序的所有 URL(/*)映射到 Acegi 过滤器链代理。Acegi 将对映射到 Acegi 过滤器链代理上的所有 URL 应用安全性。
  • 应用程序上下文加载程序位于 <listener> 标记中,它将加载 Spring 的 IOC 框架。

部署并运行应用程序

部署并运行样例应用程序非常的简单。只需要完成两件事情:

  1. 将 acegisample.war 文件从本教程下载的源代码中复制到安装 Tomcat 的 webapps 目录中。
  2. 从 Acegi Security System 主页 下载并解压缩 acegi-security-1.0.3.zip。您将找到一个名为 acegi-security-sample-tutorial.war 的样例应用程序。解压缩 war 文件并提取其 WEB-INF/lib 文件夹中所有的 jar 文件。将所有的 JAR 文件从 WEB-INF/lib 文件夹中复制到 theacegisample.war 应用程序的 WEB-INF/lib 文件夹。

现在,您已经为运行样例应用程序做好准备了。启动 Tomcat 并将浏览器指向 http://localhost:8080/acegisample/

您将看到 图 4 所示的欢迎页面,但是此时显示的页面是真实的。请继续运行程序,并查看在尝试访问欢迎页面显示的不同链接时会发生什么状况。


结束语

使用 Acegi 保护 Java 应用程序 系列的第一篇文章中,您了解了 Acegi 安全系统的特性、架构和组件,学习了大量有关 Acegi 安全过滤器的知识,这些过滤器被集成到 Acegi 的安全框架中。您还学习了如何使用 XML 配置文件配置组件依赖关系,并查看了 Acegi 的安全过滤器在样例程序中工作的情形,该应用程序可以实现基于 URL 的安全性。

本文所述的安全技术非常的简单,所以 Acegi 使用这些技术实现安全性。本系列的下一文章将开始介绍 Acegi 的一些较为高级的应用,首先是编写访问控制协议并将其存储到目录服务中。您还将了解到如何配置 Acegi,使它与目录服务交互,从而实现您的访问控制策略。


下载

描述名字大小
本文源代码j-acegi1.zip10KB

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology
ArticleID=218470
ArticleTitle=使用 Acegi 保护 Java 应用程序,第 1 部分: 架构概览和安全过滤器
publish-date=05082007