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

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

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 安全过滤器:

在访问一个安全资源之前提示用户登录。

通过检查安全标记(如密码),对用户进行身份验证。

检查经过身份验证的用户是否具有访问某个安全资源的特权。

将成功进行身份验证和授权的用户重定向到所请求的安全资源。

对不具备访问安全资源特权的用户显示 Access Denied 页面。

在服务器上记录成功进行身份验证的用户,并在用户的客户机上设置安全 cookie。使用该 cookie 执行下一次身份验证,而无需要求用户登录。

将身份验证信息存储在服务器端的会话对象中,从而安全地进行对资源的后 续请求。

在服务器端对象中构建并保存安全信息的缓存,从而优化性能。

当用户退出时,删除为用户安全会话而保存的服务器端对象。

与大量后端数据存储服务(如目录服务或关系数据库)进行通信,这些服务 用于存储用户的安全信息和 ECM 的访问控制策略。

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

架构和组件

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

四大组件

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

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

反转控制

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

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

它提供了一种语法,表示应用程序所需的组件以及这些组件如何相互依赖。

它保证了所需的组件在运行时是可用的。

XML 配置文件

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

清单 1. Spring 配置文件的结构

               value here               class="org.acegisecurity.ui.webapp.AuthenticationProcessingFitler">                  class="org.acegisecurity.providers.ProviderManager">                    

如清单 7 所示,配置所需的三个组件是 authenticationManager、 AccessDecisionManager、objectDefinitionSource:

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 过滤器链以安全地为浏览器客户机服务的容器

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

浏览器客户机向您的应用程序发送 HTTP 请求。

容器接收到 HTTP 请求并创建一个请求对象,该对象将封装 HTTP 请求中包 含的信息。容器还创建一个各种过滤器都可处理的响应对象,从而为发出请求的 客户机准备好 HTTP 响应。容器然后调用 Acegi 的过滤器链代理,这是一个代 理过滤器。该代理知道应用的过滤器的实际顺序。当容器调用代理时,它将向代 理发送请求、响应以及过滤器链对象。

代理过滤器调用过滤器链中第一个过滤器,向其发送请求、响应和过滤器链 对象。

链中的过滤器逐个执行其处理。一个过滤器可以通过调用过滤器链中下一个 过滤器随时终止自身处理。有的过滤器甚至根本不执行任何处理(比如,如果 APF 发现一个到来的请求没有要求身份验证,它可能会立即终止其处理)。

当身份验证过滤器完成其处理时,这些过滤器将把请求和响应对象发送到应 用程序中配置的拦截过滤器。

拦截器决定是否对发出请求的客户机进行授权,使它访问所请求的资源。

拦截器将控制权传输给应用程序(比如,成功进行了身份验证和授权的客户 机请求的 JSP 页面)。

应用程序改写响应对象的内容。

响应对象已经准备好了,容器将响应对象转换为 HTTP 响应,并将响应发送 到发出请求的客户机。

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

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

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

图 2. SIF 创建安全上下文

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

Acegi 的过滤器链代理调用 SIF 并向其发送请求、响应和过滤器链对象。注 意:通常将 SIF 配置为过滤器链中第一个过滤器。

SIF 检查它是否已经对这个 Web 请求进行过处理。如果是的话,它将不再进 一步进行处理,并将控制权传输给过滤器链中的下一个过滤器(参见下面的第 4 个步骤)。如果 SIF 发现这是第一次对这个 Web 请求调用 SIF,它将设置一个 标记,将在下一次使用该标记,以表示曾经调用过 SIF。

SIF 将检查是否存在一个会话对象,以及它是否包含安全上下文。它从会话 对象中检索安全上下文,并将其放置在名为 security context holder 的临时占位符中。如果不存在会话对象,SIF 将创建一个新的安全 上下文,并将它放到 security context holder 中。注意:security context holder 位于应用程序的范围内,所以可以被其他的安全过滤器访问。

SIF 调用过滤器链中的下一个过滤器。

其他过滤器可以编辑安全上下文。

SIF 在过滤器链完成处理后接收控制权。

SIF 检查其他的过滤器是否在其处理过程中更改了安全上下文(比如,APF 可能将用户详细信息存储在安全上下文中)。如果是的话,它将更新会话对象中 的安全上下文。就是说在过滤器链处理过程中,对安全上下文的任何更改现在都 保存在会话对象中。

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

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

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

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

过滤器链中前面的过滤器向 APF 发送请求、响应和过滤链对象。

APF 使用从请求对象中获得的用户名、密码以及其他信息创建身份验证标记 。

APF 将身份验证标记传递给身份验证管理器。

身份验证管理器可能包含一个或更多身份验证提供者。每个提供者恰好支持 一种类型的身份验证。管理器检查哪一种提供者支持它从 APF 收到的身份验证 标记。

身份验证管理器将身份验证标记发送到适合进行身份验证的提供者。

身份验证提供者支持从身份验证标记中提取用户名,并将它发送给名为 user cache service 的服务。Acegi 缓存了已经进行过身份验证的用 户。该用户下次登录时,Acegi 可以从缓存中加载他或她的详细信息(比如用户 名、密码和权限),而不是从后端数据存储中读取数据。这种方法使得性能得到 了改善。

user cache service 检查用户的详细信息是否存在于缓存中。

user cache service 将用户的详细信息返回给身份验证提供者。如果缓存不 包含用户详细信息,则返回 null。

身份验证提供者检查缓存服务返回的是用户的详细信息还是 null。

如果缓存返回 null,身份验证提供者将用户名(在步骤 6 中提取)发送给 另一个名为 user details service 的服务。

user details service 与包含用户详细信息的后端数据存储通信(如目录服 务)。

user details service 返回用户的详细信息,或者,如果找不到用户详细信 息则抛出身份验证异常。

如果 user cache service 或者 user details service 返回有效的用户详 细信息,身份验证提供者将使用 user cache service 或 user details service 返回的密码来匹配用户提供的安全标记(如密码)。如果找到一个匹配 ,身份验证提供者将用户的详细信息返回给身份验证管理器。否则的话,则抛出 一个身份验证异常。

身份验证管理器将用户的详细信息返回给 APF。这样用户就成功地进行了身 份验证。

APF 将用户详细信息保存在 图 2 所示由步骤 3 创建的安全上下文中。

APF 将控制权传输给过滤器链中的下一个过滤器。

一个简单的 Acegi 应用程序

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

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

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

图 4. 样例应用程序的欢迎页面:

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

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

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

配置样例应用程序

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

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

清单 8. 样例应用程序的 web.xml 文件

contextConfigLocation/WEB-INF/acegi-config.xmlAcegi Filter Chain Proxyorg.acegisecurity.util.FilterToBeanProxytargetClassorg.acegisecurity.util.FilterChainProxyAcegi Filter Chain Proxy/*org.springframework.web.context.ContextLoaderListener

web.xml 文件配置如下:

acegi-config.xml 文件的 URL 位于 标记中。

Acegi 过滤器链代理类的名称位于 标记中。

URL 到 Acegi 过滤器链代理的映射在 标记中。注 意:您可以简单地将应用程序的所有 URL(/*)映射到 Acegi 过滤器链代理。 Acegi 将对映射到 Acegi 过滤器链代理上的所有 URL 应用安全性。

应用程序上下文加载程序位于 标记中,它将加载 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,使它与目录服 务交互,从而实现您的访问控制策略。

本文配套源码

记录沿途的心情。那样的生活才是我想要的。

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

相关文章:

你感兴趣的文章:

标签云: