??xml version="1.0" encoding="utf-8" standalone="yes"?> ?pd 的前 3 部分讨论了如何?Acegi Security System 保护 Java 企业应用E序Q?/p>
W?4 部分讨论如何?Acegi 保护?servlet 容器中运行的 JavaServer Faces (JSF) 应用E序。本文首先解?Acegi 针对此目标提供的Ҏ,q澄清一些关于?Acegi ?JSF 的常见误解。然后提供一个简单的 web.xml 文gQ可以用来部|?AcegiQ从而保?JSF 应用E序。然后深入探?Acegi ?JSF lgQ了解在部v web.xml 文g和用戯?JSF 应用E序时所发生的事件。本文最后提供了一个由 Acegi 保护的示?JSF 应用E序? 回顾一下本pd的第一个示?Acegi 应用E序Q请参阅 W?1 部分 中的 “一个简?Acegi 应用E序” 一节)。该应用E序使用 Acegi 提供了以下安全特性: 回想一下,您无需~写M Java 代码p获得q些Ҏ。只需要对 Acegi q行配置。同P?JSF 应用E序中,无需~写M Java 代码Q也应该能够?Acegi 实现相同的特性?/p>
清单 1 展示了一?web.xml 文gQ通常UCؓ部v描述W?/em>Q,可以使用q个文g部v AcegiQ从而保护运行在 servlet 容器Q比?Apache TomcatQ中?JSF 应用E序Q?/p>
注意Q?a cmimpressionsent="1">清单 1 包含以下标记Q?/p>
阅读该文Ӟ了解每个标记?JSF-Acegi 应用E序中的用途?/p>
清单 1 中的每个 JSF 需? 现在看一?清单 1 中的 2 ? 例如QSpring Framework 实现一? cM圎ͼJSF 实现一? 本文E后解释不同的事g-侦听器接口,以及 Acegi ?JSF 事g-侦听器类内部执行的处理(请参?“启动 JSF-Acegi 应用E序” ?“处理对受 Acegi 保护?JSF 面的请?/a>”Q?/p>
现在看一?清单 1 中的 h?清单 1 中的 q需注意Q?a cmimpressionsent="1">清单 1 清单 1 中的 web.xml 文g中的 现在Q您已经看到Qweb.xml 文g要部|?Acegi 以保?JSF 应用E序所需的所有标记。您已经了解了侦听器、过滤器?servlet 如何怺协作。从q里的讨Z可以看出Q如果在 servlet 容器中部|?清单 1 中的 web.xml 文gQAcegi ?JSF 都试囑֜两种情Ş下进行一些处理: 接下来的两节解释每种情况中发生的一pd事g? ?1 展示了在 JSF-Acegi 应用E序启动时发生的事g序Q?/p>
详细来讲Q?a cmimpressionsent="1">?1 昄的事仉序如下所C: 下一节解?JSF-Acegi 应用E序收到来自用户的请求时发生的一pd事g?/p>
您已l了解了如何配置 Acegi 保护 JSF 应用E序。也看到了当启动 JSF-Acegi 应用E序时发生的一pd事g。本节描q当用户发送一个对?Acegi 保护?JSF 面的请求时QJSF ?Acegi lg如何?servlet 容器的框架中q行?/p>
?2 展示了当客户机发送一个对?Acegi 保护?JSF 面的请求时Q发生的事g序Q?/p>
详细来讲Q?a cmimpressionsent="1">?2 展示的事仉序如下所C: 现在Q您了解?JSF ?Acegi 如何协作提供 JSF hQ接下来看一下完成后?JSF ?Acegi?/p>
本文的下载部分(参见 下蝲Q包含一个示?JSF-Acegi 应用E序 JSFAcegiSampleQ演CZ Acegi ?JSF 的简单集成。示例应用程序?清单 1 中的 web.xml? 要部|示例应用程序,执行 W?1 部分 ?“部vq运行应用程?#8221; 一节中的两个步骤。还需要从 Sun ?JSF 站点Q参?参考资?/a>Q下载ƈ解压 jsf-1_1_01.zip。将 jsf-1.1.X.zip 中的所有文件复制到 JSFAcegiSample 应用E序?WEB-INF/lib 文g夹中?/p>
从浏览器讉K http://localhost:8080/JSFAcegiSampleQ可以调用示例应用程序。JSFAcegiSample 应用E序昄一个烦引页面和一个登录页面,索引面中包含受保护资源的链接。所有受保护面都是使用 JSF lg开发的Q?Acegi 提供d面q执行n份验证和授权?/p>
在本文中Q了解了如何配置 Acegi 以保?JSF 应用E序。还详细了解?JSF ?Acegi lg如何在一?servlet 容器的框架中协作。最后,试q行了一个示?JSF-Acegi 应用E序?/p>
关于实现 JSF 应用E序?Acegi 安全性,q涉及到更多内容。本pd的下一文章将演示如何使用 Acegi 保护?JSF 的托?bean 的访问?br />
q期共分三部分的pd文章介绍了如何?Acegi 安全pȝ保护 Java 企业应用E序。系列文章的 W?1 部分 单介l了 Acegi q解释如何用其内置的安全过滤器实现一个简单的、基?URL 的安全系l?a cmimpressionsent="1">W?2 部分 介绍了如何编写访问控制策略ƈ其保存C?LDAP 目录服务器,以及如何配置 Acegi 来与目录服务器进行交互,从而实现访问控制策略。第 3 部分Q也是本pd的最后一文章)演C如何在企业应用E序中?Acegi 保护?Java cd例的讉K? 首先我将介绍何时需要对 Java c访问进行保护,包括文中引用的两个典型企业应用程序场景。之后,我将解释 Spring 的反转控ӞIOCQ框架如何创建可?JSP ?servlet 讉K?Java cd例。我q将介绍有关 bean 代理 的重要概念,Spring 正是使用它过滤对 Java cȝ讉K。最后,我将介绍如何?Acegi 的方法安全性拦截器q行配置以控制对 Java cȝ讉K。我对 W?2 部分 中的CZE序q行增强Qؓ实现安全?Java 对象提供支持Q从而结束本pd的最后一文章? ׃本文的讨论构建在本系列前两部分的内容之上Q因此会l常引用?W?1 部分 ?W?2 部分 中的讨论和示例。因此,在l阅L文之前,在其他浏览器H口中打开前两期文章将有助于理解本文内宏V?/p>
您可能还记得Q我曑֜本系列的开头部分简单介l了 企业应用E序安全?/a>。在那次讨论中我曾提到过一U场景,其中 URL 安全性ƈ不能完全满q种场景的安全需求: 在l阅M前,误虑更多的应用程序场景,除了实现 URL 安全性以外,q些场景q要求您对单独的c访问进行保护?/p>
业务自动化应用程序中的工作流由多个流E组成。例如,病理学实验室中执行血液测试的工作由若干个步骤组成,其中每个步骤可看作一个业务流E: 很明显,每个程分别由单独的授权用户执行。未授权的用户则无权执行程。例如,实验室研Ih员只负责准备试验l果Q而无权编写测试报告?/p>
几乎所有的业务自动化应用程序都普遍使用授权的业务流E。通常Q每个业务流E被实现Z?Java c,q且需要用合适的讉K控制{略Ҏ有类实施保护?/p>
企业对企业(Business-to-businessQ集?/span> Business-to-business (B2B) 集成指一U常见的场景Q其中的两个企业实体需要彼此公开各自的特定功能。例如,N可能向旅游公司公开其房间预订功能,而后者用该功能为游客预订空闲的戉K。作为合作伙伴的旅游公司可能h一个特定的订房率。在q个场景中,N的订房系l必dҎ游公司进行n份验证,然后才能允许他们讉K所选择的类Q以便按照特定的订房率进行房间预订?/p>
现在您已l了解了?Java cȝ例的讉Kq行保护的重要性。在介绍能够实现更高U安全性的 Acegi 新功能之前,我将引导您回?Spring 框架的几个关键特性,您需要了解这些内Ҏ能l后文的CZ?/p>
首先对一?Java c进行配|ƈ执行实例化?a cmimpressionsent="1">W?1 部分 曾介l过QJava cd Spring ?XML 配置文g中进行配|。在 Spring 配置文g中配|?Java cȝq程?Acegi qo器的配置q程完全相同Q因此这里不多做介绍。相反,我们查看清?1Q它展示了名? 了解 Spring ?IOC 框架如何?XML 配置文gd Java cM息以及如何进行实例化Q这一炚w帔R要。您可能q记得,我在pd文章?W?1 部分 中用一?web.xml 文g配置 现在我们详l讨些步骤: 您现在已了解到如何从 XML 配置文g中装?bean 定义q创?Java cȝ实例。接下来Q我向您介l?Spring bean 代理q解释它对于保护 Java cd例的重要性?/p>
上一节讨Z Spring ?IOC 框架?Java 对象q行实例化。要保护?Java 对象的访问,Spring ?IOC 框架使用?bean 代理 的概c本节首先介l如何配|?bean 代理Q然后演C?Spring ?IOC 框架如何创徏代理对象?/p>
如果希望创徏 bean 代理QSpring IOC 框架要求您对代理创徏?bean 的实例进行配|。Spring ?IOC 框架使用代理创徏器创Z理对象。清?2 Z理创建器 bean 的配|文Ӟ用于保护名ؓ 如清?2 所C, 在创?bean 代理Ӟ 现在查看 清单 2 ? 现在Q您已了解了如何对希望进行保护的 bean 配置代理。接下来Q您了?Spring ?IOC 框架如何在内部ؓ应用E序?bean 创徏代理对象?/p>
?“使用 Spring 创徏 Java 对象” 的步?5 和步?6 中,您了解了 现在考虑代理创徏器如何在内部创徏代理对象Q?/p>
执行完前面的步骤后,您现在具有了所需的代理对象。因? 在前面的几节中,您了解了 Spring 如何创徏公有 bean 和私?bean。出于本文的目的Q您可将公有 bean 视ؓ使用代理保护的不安全的私?bean。现在我们来看一下客h应用E序问公?bean 和私?bean 而必遵循的一pd步骤?/p>
清单 3 展示? 应用E序可以使用清单 4 中的代码讉K清单 3 中配|的 下面进一步讨论清?4 中的步骤Q?/p>
您现在应该对 Spring 框架如何创徏 Java 对象以及客户机应用程序如何与之交互有了清晰的了解。了解了q些内容后,更加容易理解ƈ利用 Acegi 的方法安全性拦截器Q下一节将具体介绍该主题?/p>
只要应用E序试图讉K?Acegi 安全pȝ保护?bean ҎQ请求将被自动传递到 Acegi 的方法安全性拦截器。方法安全性拦截器的作用就是控制对安全 Java bean 的方法的讉K。拦截器使用 Acegi 的n份验证和授权框架认用户是否h权利调用安全 Java bean 的方法,然后相应C出响应?/p>
清单 5 展示 Acegi 的方法安全性拦截器的示例配|: 清单 5 所C的拦截器配|包含三个需要进行配|的属性,可以保护?Java bean 的访问: 回忆一下,您在本系列第 1 部分?配置w䆾验证处理qo?/a> 中曾? 您在本系列的W二文章中了解?accessDecisionManager 属性。这个访问决{管理器负责制定授权决策。在允许对一个安?bean q行讉K之前Q方法安全拦截器使用 现在查看 清单 5 中配|的 当用戯? 下一节将查看一个示?Acegi 应用E序Q它实现您目前所了解的所有概c?/p>
本文?下蝲源代?/a> 包含了一个名?AcegiMethodSecurity 的示例应用程序,可按照以下方法进行配|和部vQ?/p>
启动 Tomcat q尝试运行示例应用程序?/p>
通过从浏览器讉K http://localhost:8080/acegiMethodSecurity URL 可调用示例应用程序。AcegiMethodSecurity 昄的烦引页面包含两个链接(Catalog ?LoginQ,如图 2 所C: 当单d用程序的 Catalog 链接Ӟ它将要求您进行登录。如果以 本节演C经q增强的CZ应用E序。增强后的示例应用程序将展示 Acegi 如何使您能够在运行时向通过w䆾验证的用户时分配额外角艌Ӏ? 当安?beanQ例?清单 3 ? 在本例中QAcegi 首先查用h否经q授权来讉K安全 bean。之后,Acegi 允许用户讉K安全 bean。当安全 bean 试图讉Kq程服务Ӟ它需要用额外的业务角色。如果访问安?bean 的用户不具备额外角色Q安?bean ׃能成功访问远E服务?/p>
Acegi 框架提供了一U名?run-as-replacement 的简单机Ӟ允许您仅在方法调用期间ؓ通过w䆾验证的用户配|一个或多个额外角色。您可以使用 run-as-replacement 机制问远E应用程序的安全 bean 配置额外角色。这意味着只要安全 bean 需要访问远E应用程序,Acegi ؓ用户装蝲额外角色Q从而允许安?bean 讉Kq程应用E序?/p>
清单 6 ?清单 5 中的Ҏ安全性拦截器的配|进行了增强。增强后的配|用了 run-as-replacement 机制?/p>
清单 6 使用_体昄了两处增强(?清单 5 相比Q。第一处增Zؓ 当用戯? 本文?下蝲源代?/a> 包含一个名? d后, 在这份共分三部分的系列文章中Q我介绍了如何?Acegi 安全pȝ增强Z URL 的安全性和ZҎ的安全性。您了解了如何设计访问控制策略ƈ它们托在目录服务器中Q如何对 Acegi q行配置以与目录服务器进行通信Q以及如何根据托在服务器的讉K控制{略制定w䆾验证和授权决{?/p>
本系列的最后一文章主要介l用基于方法的安全性保?Java cd例。文章还解释?Acegi ?Spring 如何在内部创建和代理 Java 对象以及 bean 代理如何实现讉K控制。文章包含了两个CZ应用E序Q您可以使用它们q一步研I本pd中学到的概念Q更多有关?Acegi 保护 Java 应用E序的内容,请参?参考资?/a> 节?/p>
q期共分三部分的pd文章介绍了如何?Acegi 安全pȝ保护 Java 企业应用E序。在 本系列第一文?/a> 中,我介l了 Acegi q解释了如何使用安全qo器实C个简单的Z URL 的安全系l。在W二文章中Q我讨?Acegi 的更加高U的应用Q首先我编写一个访问控制策略ƈ其存储?ApacheDS 中,ApacheDS 是一个开源的 LDAP 目录服务器。我q将展示配置 Acegi 的方法,使它能够与目录服务器交互q实现您的访问控制策略。本文的l尾提供了一个示例应用程序,它?ApacheDS ?Acegi 实现了一个安全的讉K控制{略?/p>
实现讉K控制{略通常包含两个步骤Q?/p>
Acegi 减M码编写的工作Q因此在q篇文章中,我将展示如何用户和用户角色信息存储?ApacheDS 中,然后实现q些信息的访问控制策略。在该系列的最后一文章中Q我展C如何配|?AcegiQ实现对 Java cȝ安全讉K? 您可以在本文的Q何位|?下蝲样例应用E序。参?参考资?/a> 下蝲 Acegi、Tomcat ?ApacheDSQ您需要用它们运行样例代码和CZ应用E序?/p>
轻量U目录访问协议(Lightweight Directory Access ProtocolQLDAPQ可能是最行的一U定义数据格式的协议Q它针对常见的目录操作,例如对存储在目录服务器中的信息执行的d、编辑、搜索和删除操作。本节将要解释ؓ什么目录服务器是属性文件存储安全信息的首选,q展C如何在 LDAP 目录中组l和托管用户信息? 本系列第一部分向您介绍了一U简单的ҎQ可以将用户信息以属性文件的形式保存hQ参?W?1 部分Q清?6Q。属性文件以文本格式保存用户名、密码和用户角色。对于大多数真实应用E序而言Q用属性文件存储安全信息远q不够。各U各L理由表明Q目录服务器通常都是更好的选择。其中一个原因是Q真实的企业应用E序可以被大量用戯?—?通常是几千名用户Q如果应用程序将光分功能公开l用户和供应商时更是如此。频J搜索文本文件中随意存储的信息,q样做的效率q不高,但是目录服务器对q类搜烦q行了优化? W?1 部分的清?6 中的属性文件演CZ另一个原因,该文件组合了用户和角艌Ӏ在真实的访问控制应用程序中Q您通常都需要分别定义和l护用户和角色信息,q样做可以简化用户库的维护。目录服务器为更Ҏ更新用户信息提供了极大的灉|性,例如Q反映职位升q或新聘用h员。参?参考资?/a> 以了解更多关于目录服务器的用及其优点的信息?/p>
如果希望用户信息存储在一?LDAP 目录中,您需要理解一些有关目录设|的内容。本文ƈ没有提供?LDAP 的完整介l(参见 参考资?/a>Q,而是介绍了一些在试l合使用 Acegi ?LDAP 目录之前需要了解的基本概念? LDAP 目录以节Ҏ的Ş式存储信息,如图 1 所C: 在图 1 中,根节点的名称? cM圎ͼ 假设每个部门的子节点表示一l用戗因此,部门节点的子节点h不同的用h员。例如,设计部门的所有工E师都是 最后,注意 ?1 ? LDAP 使用专有名称QDNQ的概念来识?LDAP 树上特定的节炏V每个节点具有惟一?DNQ它包含该节点完整的层次l构信息。例如,?2 展示了图 1 中的一些节点的 DNQ?/p>
首先Q注意图 2 中根节点?DN。它?DN ? 每个 LDAP 属性是?RFC 定义的。LDAP 允许使用多个属性创Z?DNQ但是本文的CZ只用了以下 4 个属性: CZ使用 ׃ LDAP 相关的属性类型分到对象类中。例如,名ؓ 对象cM用承特性,q意味着 LDAP 定义了基cL保存常用属性。然后子cd对基c进行扩展,使用其定义的属性。LDAP 目录中的单个节点可以使用若干个对象类Q本文的CZ使用了以下几个对象类Q? 在真实的应用E序中,通常有关系l用L大量信息托管在一?LDAP 目录中。例如,存储每个用L用户名、密码、职U、联pL式和工资信息。ؓ单v见,下面的例子将只向您展C如何保存用户名和密码? 如前所qͼCZ使用 ApacheDSQ一U开源的 LDAP 目录服务器)演示?Acegi 是如何?LDAP 目录的。示例还使用了一个开源的 LDAP 客户机(名ؓ JXplorerQ执行简单的目录操作Q例如将信息托管?ApacheDS 上。参?参考资?/a> 以下?ApacheDS、JXplorer q了解更多有关两者协作的信息? 要创??1 所C的节点树,必须首先?ApacheDS 中创Z个根节点 可以?ApacheDS 安装中的 ~辑 清单 1 ~辑? 本文?源代码下?/a> 部分包含了编辑模式的 server.xml 文g。如果希望l学习本CZQ请?server.xml 文g从源代码中复制到您的 ApacheDS 安装目录中的正确位置Q即 ?3 所C的屏幕截图展示了在 ApacheDS 中创建根节点后,JXplorer 是如何显C根节点的Q?/p>
讄 LDAP 服务器的下一步是使用用户和组信息填充服务器。您可以使用 JXplorer ?ApacheDS 中逐个创徏节点Q但是?LDAP Data Interchange Format (LDIF) 填充服务器会更加方便。LDIF 是可被大多数 LDAP 实现识别的常见格式。developerWorks 文章很好Cl了 LDIF 文g的内容,因此本文不再做详细说明。(参见 参考资?/a> 中有?LDIF 的详l资料。) 您可以在 源代码下?/a> 部分查看 LDIF 文gQ它表示 ?1 所C的用户和部门。您可以使用 JXplorer ?LDIF 文g导入?ApacheDS。要导入 LDIF 文gQ在 JXplorer 中? ?LDIF 文g导入?ApacheDS 之后QJXplorer 显C用戯点和部门节点树,??1 所C。现在您可以开始配|?AcegiQ其能够与您的 LDAP 服务器通信?/p>
回想一下第 1 部分Q其?Acegi 使用w䆾验证处理qo器(Authentication Processing FilterQAPFQ进行n份验证。APF 执行所有后端n份验证处理Q务,例如从客hh中提取用户名和密码,从后端用户库d用户参数Q以及用这些信息对用户q行w䆾验证?/p>
您在W?1 部分中ؓ属性文件实现配|了 APFQ现在您已将用户库存储在 LDAP 目录中,因此必须使用不同的方式配|过滤器来和 LDAP 目录q行通信。首先看一下清?2Q它展示了在W?1 部分中的 “Authentication Processing Filter” 一节中如何为属性文件实现配|?APF qo器: 查看一下清?2Q您曄?APF 提供?4 个参数。您只需?LDAP 服务器中为存储重新配|第一个参敎ͼ 清单 3 展示了如何配|?Acegi 的n份验证管理器Q以实现?LDAP 服务器的通信Q?/p>
在清?3 中, LDAP w䆾验证提供者处理所有与后端 LDAP 目录的通信。您必须对其q行配置Q下一节内容将讨论该主题? 清单 4 展示?LDAP w䆾验证提供者的配置Q? 注意 LDAP w䆾验证提供者类的名UCؓ 以下节向您展C如何配|验证器和填充器 bean? 配置 在清?5 中, 目前为止Q只知道 例如Q回??2 中查? 除配|? W一? Acegi 的n份验证器? 例如Q查??2 中的 使用q种Ҏ通过 DN 模式构徏了用L DN 后, 如果目录中ƈ没有W一?DN 模式创徏?DNQ?code>authenticator bean 试使用列表中配|的W二?DN 模式。依此类推, 回想一下较早的章节 “LDAP 目录讄”Q我在将用户信息存储?LDAP 目录时添加了一点灵zL。方法是??1 所C的 如果试图使用 清单 5 中配|的M一U?DN 模式创徏特定用户?DNQ您会发现没有一U?DN 模式可用。因此,当用户尝试登录时QAcegi ? 通过允许您指定搜索过滤器QAcegi 能够处理cM的特D情cn份验证器 bean 使用搜烦qo器查找不能够通过 DN 模式构?DN q行w䆾验证的用戗? 清单 5 中的W二? 搜烦查询的参?/strong> W二个参? W三个参数是对讨?清单 5 中的 除了q三个构造器参数Q清?6 所C的 在清?7 中, W二个构造函数参数指定了 populator 前加到初始上下文?RDN。因此,RDN l成了包含组用户的节点的 DNQ例? 如您所料, q样完成了 清单 8 展示了在 Acegi 中配|初始上下文的过E: 清单 8 ?Acegi 的初始上下文cȝ名称? 您已l了解了如何用户库托管?LDAP 目录中,以及如何配置 Acegi 来用来?LDAP 目录的信息对用户q行w䆾验证。下一节将q一步介l?Acegi 的n份验证处理过滤器Q了解新配置?bean 是如何管理n份验证过E的?/p>
APF 配置完成后,能够与 LDAP 目录q行通信来对用户q行w䆾验证。如果您阅读q第 1 部分Q那么对与目录通信q程?APF 执行的一些步骤不会感到陌生,我在W?1 部分中向您展CZqo器如何用不同的服务q行用户w䆾验证。图 5 所C的序列表与您在 W?1 部分?3 看到的非常类| 无论 APF 使用属性文件进行内部的w䆾验证q是?LDAP 服务器进行通信Q步?1 到步?9 与第 1 部分是相同的。这里简单描qC?9 个步骤,您可以从步骤 10 开始l学习特定于 LDAP 的事Ӟ 不论使用何种w䆾验证ҎQ最后三个步骤是相同的(步骤21?1 ?23Q?/p>
您已l了解了 APF 对用戯行n份验证的步骤。接下来是查看成功进行n份验证的用户是否被授权访问所h的资源。这Q务由 Acegi 的拦截过滤器QInterceptor FilterQIFQ完成。本节将向您展示如何配置 IF 来实现访问控制策略? 回想一下在 W?1 部分的清?7 中配|?IF 的步骤。拦截过滤器在资源和角色之间建立映射Q就是说只有具备必要角色的用h能访问给定资源。ؓ了演C制造业企业中不同部门的业务角色Q清?9 向现有的 IF 配置d了另外的角色Q?/p>
在清?9 中,IF 包含三个参数。其中第一个和W三个参CW?1 部分中最初配|的参数相同。这里添加了W二个参敎ͼ名ؓ 在清?10 中, ?Acegi 中,投票者确定是否允许某个用戯问特定的资源。当使用 不同cd的访问决{管理器解释投票者决{的Ҏ也有所不同。清?10 所C的 Acegi 提供了若q个投票者实现类型?code>accessDecisionManager 经q验证的用户的信息(包括用户的业务角色信息)? 本文提供了一个示例应用程序,它将演示您目前掌握的 LDAP ?Acegi 概念。LDAP-Acegi 应用E序显CZ个烦引页面,该页面将设计和销售文呈现给合适的l过w䆾验证的用戗正如您看到的一PLDAP-Acegi 应用E序允许用户 在本文中Q您了解了如何将用户和业务角色信息托在 LDAP 目录中。您q详l了解了配置 Acegi 的方法,从而与 LDAP 目录交互实现讉K控制{略。在本系列最后一期文章中Q我展C如何配|?Acegi 来保护对 Java cȝ讉K?/p>
Acegi Security System 是一U功能强大ƈ易于使用的替代性方案,使您不必再ؓ Java 企业应用E序~写大量的安全代码。虽然它专门针对使用 Spring 框架~写的应用程序,但是Mcd?Java 应用E序都没有理׃M?Acegi。这份共分三部分的系列文章详l介l了 AcegiQƈ展示了如何用它保护单的企业应用E序以及更复杂的应用E序?/p>
本系列首先介l企业应用程序中常见的安全问题,q说?Acegi 如何解决q些问题。您了?Acegi 的架构模型及其安全过滤器Q后者包含了在保护应用程序中用到的大多数功能。您q将了解到各个过滤器如何单独q行工作Q如何将它们l合hQ以及过滤器如何在一个企业安全实C各U功能从头到֜链接h。本文最后通过一个样例应用程序演CZZ URL 安全pȝ?Acegi 实现。本pd后箋两篇文章探I?Acegi 的一些更高的应用,包括如何设计和托访问控制策略,然后如何去配|?Acegi 以用这些策略?/p>
您必?下蝲 AcegiQ这h能编译本文的CZ代码q运行本文的样例应用E序。还必须有作为工作站的一部分q行?Tomcat 服务器?/p>
׃企业内容理QECMQ应用程序管理存储在不同cd数据源(如文件系l、关pL据库和目录服务)中的企业内容的编写和处理QECM 安全性要求对q些数据源的讉Kq行控制。比如,一?ECM 应用E序可能会控制被授权d、编辑或删除数据的对象,而这些数据和刉业企业的设计、市销、生产以及质量控制有兟?/p>
在一?ECM 安全场景中,比较常见的就是通过对企业资源定位符Q或|络地址Q应用安全性,从而实现访问控制。这U简单的安全模型被称?em>l一资源定位W?/em> ?URL 安全性。正如我在本文后面(以及本系列后l文章)所演示的一PAcegi 为实?URL 安全性提供了全面的特性?/p>
然而,在很多企业场景中QURL 安全性还q远不够。比如,假设一?PDF 文包含某个刉业公司生的特D品的数据。文的一部分包含了将p公司的设计部门编辑和更新的设计数据。另一部分包含了生产经理将使用的生产数据。对于诸如此cȝ场景Q需要实现更加细_度的安全性,Ҏ的不同部分应用不同的访问权限?/p>
本文介绍?Acegi 为实?URL 安全性而提供的各种功能。本pd的下一文章将演示此框架的ZҎ的安全性,它提供了对企业数据访问的更细_度的控制?/p>
Acegi Security System 使用安全qo器来提供企业应用E序的n份验证和授权服务。该框架提供了不同类型的qo器,可以Ҏ应用E序的需求进行配|。您在本文后面了解?安全qo器的不同cdQ现在,只需注意可以为如下Q务配|?Acegi 安全qo器: 正如q个列表昄的那PAcegi 的安全过滤器允许您执行保护企业应用程序所需的几乎Q何事情?/p>
?Acegi 了解多Q用v来就简单。这一节介l?Acegi 的组Ӟ接下来您了解该框架如何使用反{控制QIOCQ和 XML 配置文g来组合组件ƈ表示它们的依赖关pR? Acegi Security System 由四U主要类型的lgl成Q过滤器、管理器、提供者和处理E序?/p>
Acegi 的组仉过彼此之间的依赖来对企业应用程序进行保护。比如,一个n份验证处理过滤器需要一个n份验证管理器选择一个合适的w䆾验证提供者。这是说您必须能够表示和管?Acegi lg的依赖关pR? IOC 实现通常用于理 Java lg之间的依赖关pRIOC 提供了两个重要的Ҏ: Acegi 使用 Spring 框架Q请参见 参考资?/a>Q附带的行开?IOC 实现来管理其lg。Spring 需要您~写一?XML 配置文g来表C组件的依赖关系Q如清单 1 所C: 如您所见,Acegi 使用?Spring XML 配置文g包含一? q一步解?XML 配置文g 比方_清单 1 的第一? 使用 所以在 清单 1 中,W一? 同样Q?a cmimpressionsent="1">清单 1 中的W二个和W三? qo器的 下一节将展示如何?XML 配置文g中配|?Acegi qo器。在本文后面的内容中Q您在一个样?Acegi 应用E序中用过滤器?/p>
正如我前面提到的一PAcegi 使用安全qo器ؓ企业应用E序提供w䆾验证和授权服务。您可以Ҏ应用E序的需要用和配置不同cd的过滤器。这一节将介绍五种最重要?Acegi 安全qo器?/p>
Acegi ?Session Integration FilterQSIFQ通常是您要配置的第一个过滤器。SIF 创徏了一?em>安全上下文对?/em>Q这是一个与安全相关的信息的占位W。其?Acegi qo器将安全信息保存在安全上下文中,也会使用安全上下文中可用的安全信息?/p>
SIF 创徏安全上下文ƈ调用qo器链中的其他qo器。然后其他过滤器索安全上下文q对其进行更攏V比如,Authentication Processing FilterQ我稍后进行介l)用户信息(如用户名、密码和电子邮g地址Q存储在安全上下文中? 当所有的处理E序完成处理后,SIF 查安全上下文是否更新。如果Q何一个过滤器对安全上下文做出了更改,SIF 把更改保存到服务器端的会话对象中。如果安全上下文中没有发CQ何更改,那么 SIF 删除它?/p>
?XML 配置文g中对 SIF q行了配|,如清?2 所C: Authentication Processing Filter Acegi 使用 Authentication Processing FilterQAPFQ进行n份验证。APF 使用一个n份验证(或登录)表单Q用户在其中输入用户名和密码Qƈ触发w䆾验证?/p>
APF 执行所有的后端w䆾验证处理dQ比如从客户求中提取用户名和密码Q从后端用户库中d用户参数Q以及用这些信息对用户q行w䆾验证? 在配|?APF Ӟ您必L供如下参敎ͼ APF 从用Lh对象中得到用户名、密码和其他信息。它这些信息传送给w䆾验证理器。n份验证管理器使用适当的提供者从后端用户库中d详细的用户信息(如用户名、密码、电子邮件地址和用戯问权利或ҎQ,对用戯行n份验证,q将信息存储在一? 最后,APF ? APF 的配|如清单 3 所C: 可以从这D代码中看到QAPF 依赖于上面讨论的q四个参数。每个参数都是作为清?3 所C的 Acegi 使用一?Logout Processing FilerQLPFQ管理注销处理。当客户机发来注销hӞ?LPF q行处理。它标识了来自由客户机所调用 URL 的注销h?/p>
LPF 的配|如清单 4 所C: 可以看到 LPF 在其构造方法中包含两个参数Q注销成功 URLQ?code>/logoutSuccess.jspQ和处理E序列表。注销成功 URL 用来在注销q程完成后重定向客户机。处理程序执行实际的注销q程Q我在这里只配置了一个处理程序,因ؓ只需一个处理程序就可以?HTTP 会话变ؓ无效。我在本系列下一文章中讨论更多的处理程序?/p>
Exception Translation FilterQETFQ处理n份验证和授权q程中的异常情况Q比如授权失败。在q些异常情况中,ETF 决定如何进行操作?/p>
比如Q如果一个没有进行n份验证的用户试图讉K受保护的资源QETF 显CZ个登录页面要求用戯行n份验证。类似地Q在授权p|的情况下Q可以配|?ETF 来呈C?Access Denied 面?/p>
ETF 的配|如清单 5 所C: 正如清单 5 所C,ETF 包含两个参数Q名? Acegi ?em>拦截qo?/em> 用于做出授权决策。您需要在 APF 成功执行w䆾验证后对拦截qo器进行配|,以其发挥作用。拦截器使用应用E序的访问控制策略来做出授权军_?/p>
本系列的下一文章将展示如何设计讉K控制{略Q如何将它们托管在目录服务中Q以及如何配|?Acegi 以读取您的访问控制策略。但是,目前我将l箋向您展示如何使用 Acegi 配置一个简单的讉K控制{略。在本文后面的部分,您将看到使用单的讉K控制{略构徏一个样例应用程序?/p>
配置单的讉K控制{略可分Z个步骤: 步骤 1. ~写单的讉K控制{略 清单 6 所C的讉K控制{略定义了用户名 步骤 2. 配置 Acegi 的拦截过滤器 如清?7 所C,配置所需的三个组件是 正如您已l了解到的一PAcegi 的组件彼此依赖,从而对您的应用E序q行保护。在本文后面的部分,您将看到如何?Acegi q行配置Q从而按照特定的序应用安全qo器,因此需要创?em>qo器链。出于这个目的,Acegi 保存了一个过滤器铑֯象,它封装了Z护应用程序而配|了的所有过滤器。图 1 展示?Acegi qo器链的生命周期,该周期从客户机向您的应用E序发?HTTP h开始。(?1 昄了服务于览器客h的容器。) 下面的步骤描qCqo器链的生命周期: 为帮助您q一步理?Acegi qo器,我将详细探讨其中两个qo器的操作QSession Integration Filter ?Authentication Processing Filter?/p>
?2 展示?SIF 创徏安全上下文所涉及到的步骤Q?/p>
现在详细地考虑下面q些步骤Q?/p>
?3 展示?APF 对用戯行n份验证所涉及到的步骤Q?/p>
现在仔细考虑以下q些步骤Q?/p>
在本文中Q您已经了解了很多关?Acegi 的知识,所以现在看一下利用您目前学到的知识能做些什么,从而结束本文。对于这个简单的演示Q我设计了一个样例应用程序(参见 下蝲Q,q对 Acegi q行了配|以保护它的一些资源? 样例应用E序包含 5 ?JSP 面Qindex.jsp、protected1.jsp、protected2.jsp、login.jsp ?accessDenied.jsp?/p>
index.jsp 是应用程序的Ƣ迎面。它向用hCZ三个链接,如图 4 所C: ?4 所C的链接中,其中两个链接指向了被保护的资源(protected1.jsp ?protected2.jspQ,W三个链接指向登录页面(login.jspQ。只有在 Acegi 发现用户没有被授权访问受保护的资源时Q才会显C?accessDenied.jsp 面?/p>
如果用户试图讉KM受保护的面Q样例应用程序将昄d面。当用户使用d面q入后,应用E序自动重定向到被h的受保护资源?/p>
用户可以通过单击Ƣ迎面中的W三个链接直接请求登录页面。这U情况下Q应用程序显C用户可以进入系l的d面。进入系l以后,应用E序用户重定向?protected1.jspQ它是用戯入系l而没有请求特定的受保护资源时昄的默认资源?/p>
为本文下载的源代码包含一个名?acegi-config.xml ?XML 配置文gQ它包含 Acegi qo器的配置。根?安全qo器的讨论 中的CZQ您应该很熟悉这些配|?/p>
我还为样例应用程序编写了一? web.xml 文g配置如下Q?/p>
部vq运行样例应用程序非常的单。只需要完成两件事情: 现在Q您已经行样例应用程序做好准备了。启?Tomcat q将览器指? 您将看到 ?4 所C的Ƣ迎面Q但是此时显C的面是真实的。请l箋q行E序Qƈ查看在尝试访问欢q页面显C的不同链接时会发生什么状c?/p>
?em>使用 Acegi 保护 Java 应用E序 pd的第一文章中Q您了解?Acegi 安全pȝ的特性、架构和lgQ学习了大量有关 Acegi 安全qo器的知识Q这些过滤器被集成到 Acegi 的安全框架中。您q学习了如何使用 XML 配置文g配置lg依赖关系Qƈ查看?Acegi 的安全过滤器在样例程序中工作的情形,该应用程序可以实现基?URL 的安全性? 本文所q的安全技术非常的单,所?Acegi 使用q些技术实现安全性。本pd的下一文章开始介l?Acegi 的一些较为高U的应用Q首先是~写讉K控制协议q将其存储到目录服务中。您q将了解到如何配|?AcegiQ它与目录服务交互Q从而实现您的访问控制策略?/p>
Bilal Siddiqui 是一名电子工E师、XML NQ他q是 WaxSysQ主要从事电子商务简化)的创之一。自?1995 q毕业于拉合工E技术大学(University of Engineering and TechnologyQLahoreQ电子工E专业以后,他就开始ؓ工业控制pȝ设计各种软g解决Ҏ。稍后,他致力于 XML 斚wq用他?C++ ~程中取得的l验来构建基?Web ?WAP ?XML 处理工具、服务器端解析方案和服务应用E序。Bilal 是一名技术推q者,q且是一名多产的技术作家?/p>
Bilal Siddiqui l在他的 pd文章 中展C如何?Acegi 保护 Java™Server Faces (JSF) 应用E序。配|?JSF ?AcegiQ让它们?servlet 容器中协作,探烦 JSF ?Acegi lg如何彼此协作?/blockquote>
回页?/strong>
清单 1. 用于部v Acegi ?servlet 容器中的 JSF ?web.xml 文g
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/acegi-config.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
com.sun.faces.config.ConfigureListener
</listener-class>
</listener>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<!-- Acegi filter configuration -->
<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>
<!-- Acegi Filter Mapping -->
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
<context-param>
标记
<listener>
标记
<filter>
标记
<servlet>
标记
<servlet-mapping>
标记
<filter-mapping>
标记 <context-param>
标记定义一个参敎ͼ?Acegi ?JSF 在启动或执行期间使用。第一个参??contextConfigLocation
?定义 Acegi ?XML 配置文g的位|?/p>
javax.faces.STATE_SAVING_METHOD
?javax.faces.CONFIG_FILES
参数?code>javax.faces.STATE_SAVING_METHOD 参数指定希望在客hq是服务器上存储 JSF 面-视图状态。Sun 的参考实现的默认行ؓ是将 JSF 视图存储在服务器上?/p>
javax.faces.CONFIG_FILES
参数指定 JSF 需要的配置文g的位|。JSF 配置文g的详l信息不属于本文讨论的范_参见 参考资?/a>Q获取涉及该主题的资源链接)?/p>
<listener>
标记?code><listener> 标记定义侦听器类Q侦听器cM听ƈ处理 JSP ?servlet 应用E序启动和执行期间发生的事g。例如:
<listener>
标记像一U可扩展性机Ӟ允许?servlet 容器内部q行的应用程序协同某些事件进行处理。servlet 规范定义了侦听器cMؓ处理事g而实现的一些接口?/p>
javax.servlet.ServletContextListener
servlet 接口。实现此接口?spring cL org.springframework.web.context.ContextLoaderListener
。注意,q是 清单 1 的第一?<listener>
标记中的侦听器类?com.sun.faces.config.ConfigureListener
c,该类实现一些事?侦听接口。可以在 清单 1 的第二个 <listener>
标记中找?ConfigureListener
cR?/p>
<filter>
标记。在h?servlet 处理传入的请求之前,servlet 应用E序使用qo器对其进行预处理。在h执行之前QAcegi 使用 servlet qo器对用户q行w䆾验证?/p>
<filter>
标记Q它?<filter-class>
子标记指定一?org.acegisecurity.util.FilterToBeanProxy
cR?code>FilterToBeanProxy cL Acegi 的一部分。此cdC?javax.servlet.Filter
接口Q该接口?servlet 应用E序的一部分?code>javax.servlet.Filter 接口有一?doFilter()
ҎQservlet 容器在收到请求时调用该方法?/p>
<filter>
标记有另一个子标记 <init-param>
?code><init-param> 标记指定实例?FilterToBeanProxy
cL需的参数。可以从 清单 1 中看出,FilterToBeanProxy
cd需要一个参敎ͼ该参数是 FilterChainProxy
cȝ一个对象?code>FilterChainProxy c表C?W?1 部分 1 中讨论的整个 Acegi qo器链Q请参阅 “安全qo?#8221; 节Q?code>FilterToBeanProxy cȝ doFilter()
Ҏ使用 FilterChainProxy
cL?Acegi 的安全过滤器链?/p>
<filter-mapping>
标记指定调用 Acegi ?FilterToBeanProxy
的请?URL。我已经所有的 JSF 面映射?Acegi ?FilterToBeanProxy
。这意味着只要用户试图讉K JSF 面Q?code>FilterChainProxy doFilter()
Ҏ׃自动获得控制权?/p>
<servlet>
标记指定希望从特?URl 调用?servletQ在本例中是一?JSF servletQ?code><servlet-mapping> 标记定义?URL。几乎所有的 JSP ?servlet 应用E序都包含这两个标记Q所以无需再作讨论Q参?参考资?/a>Q获取讨?servlet ~程的资源链接)?/p>
回页?/strong>
?1. JSF-Acegi 应用E序启动时发生的事g序
ContextLoaderListener
注册Z个侦听器c,该类实现 javax.servlet.ServletContextListener
接口?code>ServletContextListener 接口包含两个重要ҎQ?code>contextInitialized() ?contextDestroyed()
Q?
contextInitialized()
Ҏ在初始化 servlet 上下文时获得控制权?
ConfigureListener
注册为另一个侦听器。JSF ?ConfigureListener
实现许多侦听器接口,比如 ServletContextListener
?ServletContextAttributeListener
?ServletRequestListener
Q以?ServletRequestAttributeListener
。您已经看到?ServletContextListener
接口的方法。余下的接口是:
ServletContextAttributeListener
Q它包含 3 U方法:attributeAdded()
attributeRemoved()
?attributeReplaced()
。这 3 U方法分别在某个属性被d?servlet 上下文、被?servlet 上下文删除、被新属性取代时获得控制权?code>attributeReplaced() Ҏ?处理对受 Acegi 保护?JSF 面的请?/a> 节的第 8 步中获得控制权?br />
ServletRequestListener
中包含的Ҏ在创建或删除新的 servlet h对象时获得控制权。servlet hҎ表示q包装来自用Lh?br />
ServletRequestAttributeListener
中包含的Ҏ在添加、删除或替换某个h对象的属性时获得控制权。本文稍后将讨论?处理对受 Acegi 保护?JSF 面的请?/a> 节的第 3 步中创徏一个新的请求对象时QJSF ?ConfigureListener
执行的处理?
ContextLoaderListener
Qservlet 上下文是通过调用 ContextLoaderListener
?contextInitializated()
Ҏ初始化的?br />
contextInitialized()
Ҏ解析 Acegi 的配|文Ӟ?JSF-Acegi 应用E序创徏 Web 应用E序上下文,以及实例化所有的安全qo器和?Acegi 配置文g中配|的 Jave bean。在以后 JSF 应用E序收到来自客户机的hӞq些qo器对象将会用于n份验证和授权Q参?W?3 部分 中关?Web 应用E序上下文创建的讨论和图 1Q?
ConfigureListener
Qservlet 上下文是通过调用 contextInitialized()
Ҏ初始化的?br />
contextInitialized()
Ҏ查在 JSF 配置文g中配|的所?JSF 托管 beanQ确?Java cM每个 bean q存?br />
FilterToBeanProxy
Qservlet 容器其实例化、初始化q注册ؓ一个过滤器。Acegi 现在可以对传入的h执行w䆾验证和授权了?
回页?/strong>
?2. JSF ?Acegi 协作提供 JSF 面
ConfigureListener
实现 ServletRequestListener
接口。这意味着 ConfigureListener
侦听与创建和删除 servlet h对象相关的事件。因此,servlet 容器调用 ConfigureListener
cȝ requestInitialized()
Ҏ?br />
requestInitialized()
Ҏ准备执行h?JSF 生命周期。准备过E包括检查请求的 faces 上下文是否存在。faces 上下文封装与应用E序资源相关的信息。faces servlet 执行 JSF 生命周期旉要这些信息。如果此h是新会话的第一个请求,׃~少 faces 上下文。在q种情况下,requestInitialized()
Ҏ创徏一个新?faces 上下文?br />
<filter-mapping>
标记?<url-pattern>
子标C。如果请?URL 与这?URL 模式匚wQservlet 容器调用 Acegi ?FilterToBeanProxy
Q?code>FilterToBeanProxy 已在 ?1 的第 9 步中被注册ؓ一?servlet qo器?br />
FilterToBeanProxy
使用 FilterChainProxy
cL?Acegi 的完整的安全qo器链。Acegi 的过滤器自动查第 4 步中创徏?HTTP 会话对象Q以查看h客户机是否已被验证。如?Acegi 发现用户未被验证Q它提供一个登录页面。否则,它就直接执行 W?2 部分 ?“配置拦截?#8221; 一节中描述的授权过E?
ConfigureListener
?attributeReplaced()
ҎQservlet 上下文已被更新?code>ConfigureListener 查是否有M JSF bean 被更攏V如果发CQ何更改,它相应地更新 faces 上下文。但是,在本例中Q在w䆾验证q程?Acegi 没有更改M JSF 托管 beanQ因此在此调用期?ConfigureListener
不进行Q何处理?br />
回页?/strong>
来自: http://www.cnblogs.com/amboyna/archive/2008/03/25/1122089.html
]]>本文?Acegi Security Systerm 介绍的最后一部分Q共三部分)QBilal Siddiqui 向您介l如何保护对 Java cd例的讉KQ从而结束本pd文章。通过本文了解Z需要对 Java™ cȝ讉Kq行保护QSpring 如何创徏和保护对 Java cd例的讉K以及如何?Acegi q行配置以实?Java 应用E序的类安全性?/blockquote>
假设有这样一?PDF 文Q其中包含了某制造业公司生的特定品的数据。文档的一部分包含了设计数据,由公司设计部分q行~辑和更新。文另一部分包含生l理用到的生产数据。对于此cd景,需要实现更加细_度的安全性,Ҏ档的不同部分应用不同的访问权限?/blockquote>
回页?/strong>
publicCatalog
?bean 的配|:
清单 1. Acegi XML 配置文g
<beans>
<bean id="publicCatalog"
class="com.catalog.PublicCatalog" />
<!--Other bean tags -->
<beans>
<listener>
标记Q它指向名ؓ ContextLoaderListener
的类?code>ContextLoaderListener 装蝲 Spring ?IOC 框架q创?Java 对象。您可以参?W?1 部分的清?8 查看全部内容。图 1 也对此进行了描述Q?/p>
?1. 装蝲 Spring ?IOC 框架q创?Java 对象
ContextLoaderListener
cd用程序正在启动?br />
ContextLoaderListener
cdZ?Web 应用E序上下文以保存应用E序中特定于 Spring 的资源信息。借助 Spring ?IOC 框架Q您可以装蝲自己的自定义应用E序上下文。要创徏应用E序上下文,用名?ContextLoader
的上下文装蝲器类装蝲应用E序上下文?br />
XMLWebApplicationContext
的类Q它?Spring 框架的一部分q提供可处理 Spring XML 配置文g的功能。Acegi 应用E序使用的是 Spring ?XML 配置文gQ因此本文仅讨论?XMLWebApplicationContext
c表C的应用E序上下文。在本例中,上下文装载器?XMLWebApplicationContext
c进行实例化Q后者表C您?Acegi 应用E序的应用程序上下文。上下文装蝲器还?Web 应用E序上下文中讄 servlet 上下文(于步?1 中创建)的引用?br />
XMLWebApplicationContext
cd XML 配置文gq行解析Q获得关?Java cȝ信息q将信息装蝲到其他内部对象中?br />
XMLWebApplicationContext
cd XML 配置文g中指定的所?Java c进行实例化?code>XMLWebApplicationContext cL?XML 配置文g中经q配|的 Java bean 是否依赖其他?Java 对象。如果是的话Q?code>XMLWebApplicationContext cd首先对其?bean 所依赖?bean q行实例化。通过q种方式Q?code>XMLWebApplicationContext cdZ XML 配置文g中定义的所?bean 的实例。(注意Q步?6 假定 XML 配置文g中所?bean 都不要进行保护,E后一节将介绍步骤 5 和步?6 之间执行的额外步骤,从而保护对此处创徏?Java bean 的访问)?br />
XMLWebApplicationContext
cd所?bean 保存在一个数l中?
回页?/strong>
privateCatalog
?Java 对象Q?/p>
清单 2. 代理 bean 配置
<bean id="proxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>privateCatalog</value>
<!--Names of other beans to be proxied -->
</list>
</property>
<property name="interceptorNames">
<list>
<value>privateCatalogSecurityInterceptor</value>
</list>
</property>
</bean>
<bean>
标记h一?class
属性,其gؓ org.springframework.aop.framework.autoproxy. BeanNameAutoProxyCreator
?code>BeanNameAutoProxyCreator cL Spring IOC 框架的一部分Q可以自动创?bean 代理。Spring 框架提供?BeanPostProcessor
接口Q它提供了一U可扩展机制Q允许应用程序编写自q逻辑来创?bean 代理。Spring ?BeanNameAutoProxyCreator
cdC BeanPostProcessor
接口q提供所有必需的代理创建逻辑来保?Java cR因此,本文中您无需实现 BeanPostProcessor
接口?/p>
BeanNameAutoProxyCreator
cMؓ所有由 beanNames
属性定义的 bean 创徏代理Q参?清单 2 ?<bean>
标记的第一?<property>
子元素)?code>beanNames 属性在 <list>
标记中包含一?bean 名称列表。在 清单 2 中,我只对希望ؓ之创Z理的 privateCatalog
beanq行了配|?/p>
<bean>
标记的第二个 <property>
子元素。它指定了名?interceptorNames
的代理,它将一个或多个拦截器的名称装h。我在后文详细讨论拦截器概c现在,只需了解拦截器可以拦截用户ƈ在用戯?bean 之前实现讉K控制{略?/p>
XMLWebApplicationContext
cd何从 XML 配置文g中读?bean 定义q后创?bean 实例。在创徏 bean 实例之前Q?code>XMLWebApplicationContext cd?XML 配置文g是否包含M代理创徏?beanQ即实现 BeanPostProcessor
接口?beanQ配|。如果存在该 beanQ它要求代理创建器为您希望q行保护?bean 创徏 bean 代理?/p>
BeanNameAutoProxyCreator
c)装蝲 清单 2 中配|的 beanNames
属性文件中指定的所?bean 名称?br />
class
属性?br />
interceptorNames
属性中指定的拦截器的实例?br />
Cglib2AopProxy
cȝ实例Q将所?bean 名称Q步?2Q和拦截器(步骤 3Q传递到 Cglib2AopProxy
cR?code>Cglib2AopProxy cL Spring 框架的一部分q用于生成动态代理对象。在本例中,Cglib2AopProxy
cd创徏安全 bean 讉K控制所需的代理对象?Cglib2AopProxy
cdC两个名ؓ AOPProxy
?MethodInterceptor
的接口?code>AOPProxy 接口?Spring 框架提供Q表C您希望q行代理的实?beanQ因此它与您?bean 公开相同的方法?code>MethodInterceptor 接口也源?AOP 框架Q它包含的方法可以在用户试图讉K您已执行代理?bean 时接受控制权。这意味着 MethodInterceptor
接口处理来自用户的请求以讉K执行q代理的 bean。由?Cglib2AopProxy
cd时实C AOPProxy
?MethodInterceptor
接口Q因此它提供了完整的功能Q既可以提供l过代理?beanQ也可以处理用户h以访问代?beanQ参?参考资料小?/a> 中有?AOP 的讨论文章的链接Q?/p>
XMLWebApplicationContext
cd安全 bean 的代理(而不是实际的 beanQ保存在 “使用 Spring 创徏 Java 对象” 的步?7 中的同一个数l中?
回页?/strong>
publicCatalog
?privateCatalog
两个 bean ?XML 配置?code>publicCatalog bean 意味着公共讉KQ因此不需要?bean 代理?code>privateCatalog bean 意味着只能由指定用戯问,因此必须加以保护。我在清?3 中包含了 privateCatalog
bean ?bean 代理配置Q?/p>
清单 3. publicCatalog ?privateCatalog bean ?XML 配置
<beans>
<bean id="publicCatalog" class="sample.PublicCatalog"/>
<bean id="privateCatalog" class="sample.PrivateCatalog"/>
<!-- proxy configuration for privateCatalog bean -->
<bean id="proxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>privateCatalog</value>
<!--Names of other beans to be proxied -->
</list>
</property>
<property name="interceptorNames">
<list>
<value>privateCatalogSecurityInterceptor</value>
</list>
</property>
</bean>
<beans>
publicCatalog
?privateCatalog
Java bean。注意,清单 4 中显C的 Java 代码可位?JSP 面或位于服务器?Java 应用E序?bean 中?/p>
清单 4. 讉K安全和不安全 Java bean 的客h应用E序代码
//Step 1: Fetching an instance of the application context
XMLWebApplicationContext applicationCtx =
WebApplicationContextUtils.getWebApplicationContext(
this.getServletConfig().getServletContext());
//Step 2: Fetching an insecure bean from the application context
PublicCatalog publicCatalog =
(PublicCatalog) applicationCtx.getBean("publicCatalog");
//Step 3: Calling a method of the insecure bean
String publicData = publicCatalog.getData();
//Step 4: Fetching a secure bean from the application context
PrivateCatalog privateCatalog =
(PrivateCatalog) applicationCtx.getBean("privateCatalog");
//Step 5: Calling a method of the secure bean
String privateData = privateCatalog.getData();
当应用程序希望访?XML 配置文g中配|的 Java bean Ӟ它必d回您?“使用 Spring 创徏 Java 对象” 的步?4 中见到的 XMLWebApplicationContext
对象?code>XMLWebApplicationContext 对象包含?XML 配置文g配置的所?Java beans 的引用?br />
您现在具有一个对 XMLWebApplicationContext
对象的引用?code>XMLWebApplicationContext cd开了一?getBean()
ҎQ它包含 bean 的名Uƈ在数l中查找 “使用 Spring 创徏 Java 对象” 步骤 7 中准备的 bean。在本例中,?bean ?publicCatalog
Q未执行q代理)Q因?XMLWebApplicationContext
返回实际的 bean?br />
现在您可以调用步?2 中获得的 publicCatalog
bean 的Q何方法。例如,清单 4 昄?getData()
Ҏ调用的执行没有应用Q何访问控制ƈ向应用程序返回类别数据?br />
安全 bean 与不安全 bean 的取回方式类|惟一区别是:当您通过调用 getBean()
Ҏ试取回安全 bean Ӟ您将获得安全对象的代理而不是实际的对象。该代理是我在 “Spring IOC 发挥效用” 步骤 4 中解释的?Spring 框架创徏的同一个对象?br />
当调用安?bean 的方法时Q您?步骤 4 中获得的代理对象一个方法调用请求分配给拦截器。拦截器检查试图访问方法的用户是否h相应的访问权Q从而处理方法调用请求?
回页?/strong>
清单 5. Acegi 的方法安全性拦截器的示例配|?/strong>
<bean id="privateCatalogSecurityInterceptor"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<value>
sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING
<!-- Roles required by other beans -->
</value>
</property>
</bean>
authenticationManager
?code>accessDecisionManager ?objectDefinitionSource
?/p>
authenticationManager
属性进行了配置?code>authenticationManager 属性的作用是对用户q行w䆾验证?/p>
authenticationManager
?accessDecisionManager
属性对用户q行w䆾验证和授权?/p>
objectDefinitionSource
属性。它cM于第 1 部分中出现的 objectDefinitionSource 属性。以前的 objectDefinitionSource 包含cM?/protected/*
?/**
q样?URLQ清?5 中的 objectDefinitionSource
属性指定类和方法名Q例如,sample.PrivateCatalog
是之前执行过代理的类的名Uͼ?getData
是您希望对其控制用户讉K的方法的名字?/p>
PrivateCatalog
bean ?getData()
ҎӞ控制权将自动传递给拦截器。拦截器使用 Acegi 框架查用L业务角色是否?ROLE_HEAD_OF_ENGINEERING
Q特定于本文的示例)。如果是的话Q拦截器允许对 getData()
Ҏq行讉K。如果拦截器发现用户角色不是 ROLE_HEAD_OF_ENGINEERING
Q则拒绝讉K?/p>
回页?/strong>
alice
?code>bob ?specialUser
Q?br />
?2. CZ应用E序的主面
alice
?specialUser
的n份进行登录,CZ应用E序提?em>完整?/em> cdQ包括公有数据和U有数据。这是因为在 清单 5 中,您对Ҏ安全性拦截器q行了配|,允许用户使用 ROLE_HEAD_OF_ENGINEERING
讉KU有cdQ?alice
?specialUser
都具有该讉K权。另一斚wQ如果您?bob
的n份登录,CZ应用E序仅昄公有数据?/p>
回页?/strong>
privateCatalog
beanQ要讉K一个原创资源时Q您可能需要用额外的角色。例如,您可能考虑到您的安?bean 需要通过 Java ?Remote Method Invocation (RMI) 框架或一?Web 服务讉K某个q程应用E序。访问安?bean 的用户不会占用远E应用程序要求访问用h具备的业务角艌Ӏ?/p>
清单 6. Acegi Ҏ安全性拦截器的增强配|?/strong>
<bean id="privateCatalogSecurityInterceptor"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="runAsManager">
<bean id="runAsManager"
class="org.acegisecurity.runas.RunAsManagerImpl">
<property name="key">
<value>myKeyPass</value>
</property>
</bean>
</property>
<property name="objectDefinitionSource">
<value>
sample.PrivateCatalog.getData=ROLE_HEAD_OF_ENGINEERING,RUN_AS_MANAGER
</value>
</property>
</bean>
runAsManager
属性?code>runAsManager 属性的作用是向通过w䆾验证的用户动态添加角艌Ӏ出于这个目的,runAsManager
属性包含了 RunAsManagerImpl
bean 的定义?code>RunAsManagerImpl bean 只有在满下面的条g时才可变为活跃状态:?objectDefinitionSource
Ҏ的角色定义中扑ֈ?RUN_AS_
为前~的角艌Ӏ例如,PrivateCatalog.getData()
Ҏ的角色定义(清单 6 中以_体昄的第二处增强Q具有一?RUN_AS_MANAGER
角色?/p>
RunAsManagerImpl
bean 包含一个名?key
的属性,它封装的加密键用于确保只额外的角色作ؓ run-as-replacement E序的一部分生成?/p>
getData()
ҎӞRunAsManagerImpl
bean 变ؓz跃状态ƈ创徏名ؓ RUN_AS_MANAGER
的额外角Ԍ从而启?getData()
Ҏ讉Kq程应用E序?/p>
EnhancedAcegiMethodSecurity
的示例应用程序,它可以演C?run-as-replacement 机制和程序。该应用E序显CZ个具?Catalog 链接的烦引页面。如果单?Catalog 链接Q将要求q行d?/p>
EnhancedAcegiMethodSecurity
应用E序ؓ您提供登录用户及其角色的完整信息。例如,如果?alice
?specialUser
w䆾dQ将向您昄用户的所有业务角Ԍ包括额外创徏的时的 RUN_AS_MANAGER
角色?/p>
来自:http://www-128.ibm.com/developerworks/cn/java/j-acegi3/?
]]>了解?Acegi 安全pȝQAcegi Security SystemQ的 基础知识 后,我们介l该pȝ的更加高U的应用。在本文中,Bilal Siddiqui 向您展示了如何结合?Acegi 和一?LDAP 目录服务器,实现灉|的具有高性能?Java™ 应用E序的安全性。还了解如何编写访问控制策略ƈ其存储?ApacheDS 中,然后配置 Acegi 使其与目录服务器交互Q从而实现n份验证和授权的目的?/blockquote>
?1. LDAP 目录的树状结?/strong>
org
。根节点可以装与不同企业有关的数据。例如,本系列第 1 部分开发的刉业企业被显CZؓ org
节点的直接子节点。该刉业企业h两个名ؓ departments
?partners
的子节点?/p>
partners
子节点封装了不同cd的合作伙伴。图 1 所C的三个分别?customers
?code>employees ?suppliers
。注意,q三U类型的合作伙伴其行Z企业pȝ用户一栗每一U类型的用户所扮演的业务角色不同,因此讉Kpȝ的权利也不同?departments
节点包含该制造业企业的不同部门的数据 —?例如 engineering
?marketing
字节炏V每个部门节点还包含一l或多组用户。在 ?1 中,engineers
l是 engineering
部门的子节点?/p>
engineering
部门?engineers
l的成员?/p>
departments
节点的最后一个子节点?code>specialUser 是一名用P而非一l用戗在目录讄中,?alice
?bob
之类的用户一般都包含?partners
节点中。我这个特D用户包含在 departments
节点中,以此证明 Acegi 允许用户位于 LADP 目录中Q何地点的灉|性。稍后在本文中,您将了解如何配置 Acegi 以应?specialUser
?/p>
?2. LDAP 目录节点的专有名U?/strong>
dc=org
Q这是与 org
根节点相关的属性值对。每个节炚w有若q个与之相关的属性?code>dc 属性代?“domain component” q由 LDAP RFC 2256 定义Q参?参考资?/a> 中有兛_?RFC 文的链接)QLDAP 目录中的根节炚w常表示Z个域lg?/p>
dc
Q域lgQ?
o
Q组l)
ou
Q组l单元)
uid
Q用?IDQ?dc
表示域,?o
表示l织名称Q?code>ou 表示l织的不同单元,?uid
表示用户?/p>
org
是根节点Q其 DN 只需指定自n的名Uͼdc=org
Q。比较一下,manufacturingEnterprise
节点?DN ?o=manufacturingEnterprise,dc=org
。当向下Ud节点树时Q每个父节点?DN 被包含在其子节点?DN 中?organizationalPerson
的对象类所包含的属性定义了在组l内工作的h员(例如Q职U、常用名、邮寄地址{等Q?
中所有的l节点(例如
dc
属性是强制性的?br />
manufacturingEnterprise
?br />
departments
节点及其子节炏V?
member
属性,该属性包含一个用户列表?a cmimpressionsent="1">?1engineers
节点Q?member
属性指定该l的成员。而且Q示例?groupOfNames
对象cȝ ou
Q组l单元)属性指定组用户的业务角艌Ӏ?br />
alice
节点Q?
回页?/strong>
org
。ApacheDS 为此提供了一?XML 配置文g。XML 配置文g定义了一l可q行配置?beanQ从而根据应用程序的需求定制目录服务器的行为。本文只解释创徏根节Ҏ需的配|?/p>
conf
文gҎ到名?server.xml
?XML 配置文g。打开文g后,会发现很?bean 配置cM?Acegi 的过滤器配置。查扑?examplePartitionsConfiguration
?bean。该 bean 控制 ApacheDS 上的分区。当创徏新的根节ҎQ实际上在 LDAP 目录上创Z个新的分区?/p>
examplePartitionConfiguration
bean 以创?org
根节点,如清?1 所C:
清单 1. ~辑模式?examplePartitionConfiguration bean 配置
<bean id="examplePartitionConfiguration" class=
"org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration"
>
<property name="suffix"><value>dc=org</value></property>
<property name="contextEntry">
<value>
objectClass: top
objectClass: domain
dc: org
</value>
</property>
<!-- Other properties of the examplePartitionConfiguration bean, which you don't
need to edit. -->
</bean>
examplePartitionConfiguration
bean 的两个属性:
suffix
Q它定义Ҏ目的 DN?br />
contextEntry
Q定?org
节点用的对象cR注意,org
根节点用两个对象类Q?code>top ?domain
?conf
文g夏V?/p>
?3. JXplorer 昄根节?/strong>
LDIF
菜单Q如?4 所C:
?4. ?LDIF 文g导入?ApacheDS
回页?/strong>
清单 2. 为属性文仉|?APF
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureUrl"
value="/login.jsp?login_error=1" />
<property name="defaultTargetUrl"
value="/index.jsp" />
<property name="filterProcessesUrl"
value="/j_acegi_security_check" />
</bean>
authenticationManager
Q即可。其他三个参C持不变?/p>
清单 3. ?LDAP 配置 Acegi 的n份验证管理器
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="ldapAuthenticationProvider" />
</list>
</property>
</bean>
org.acegisecurity.providers.ProviderManager
是一个管理器c,它管?Acegi 的n份验证过E。ؓ此,w䆾验证理器需要一个或多个w䆾验证提供者。您可以使用理?bean 的提供者属性来配置一个或多个提供者。清?3 只包含了一个提供者,?LDAP w䆾验证提供者?
清单 4. 配置 LDAP w䆾验证提供?/strong>
<bean id="ldapAuthenticationProvider"
class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
<constructor-arg><ref local="authenticator"/></constructor-arg>
<constructor-arg><ref local="populator"/></constructor-arg>
</bean>
org.acegisecurity.providers.ldap.LdapAuthenticationProvider
。其构造函数包含两个参敎ͼ使用两个 <constructor-arg>
标记的Ş式,如清?4 所C?/p>
LdapAuthenticationProvider
构造函数的W一个参数是 authenticator
Q该参数通过查用L用户名和密码?LDAP 目录的用戯行n份验证。完成n份验证后Q第二个参数 populator
从 LDAP 目录中检索有兌用户的访问权限(或业务角Ԍ信息?
回页?/strong>
authenticator
bean 检查具有给定用户名和密码的用户是否存在?LDAP 目录中。Acegi 提供了名?org.acegisecurity.providers.ldap.authenticator.BindAuthenticator
的验证器c,它将执行验证用户名和密码所需的功能?/p>
authenticator
beanQ如清单 5 所C:
清单 5. 配置验证?bean
<bean id="authenticator"
class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg><ref local="initialDirContextFactory"/></constructor-arg>
<property name="userDnPatterns">
<list>
<value>uid={0},ou=employees,ou=partners</value>
<value>uid={0},ou=customers,ou=partners</value>
<value>uid={0},ou=suppliers,ou=partners</value>
</list>
</property>
<property name="userSearch"><ref local="userSearch"/></property>
</bean>
BindAuthenticator
构造函数具有一个参敎ͼ使用 <constructor-arg>
标记的Ş式。清?5 中参数的名称?initialDirContextFactory
。该参数实际上是另一?beanQ稍后您学习如何配|该 bean?/p>
initialDirContextFactory
bean 的作用就是ؓE后的搜索操作指定初始上下文。初始上下文是一?DNQ它指定?LDAP 目录内某个节炏V指定初始上下文后,在该节点的子节点中执行所有的搜烦操作Q例如查扄定用P?/p>
partners
节点Q它?DN ?ou=partners,o=manufacturingEnterprise,dc=org
。如果将 partners
节点指定为初始上下文QAcegi 只?partners
节点的子节点中查扄戗?BindAuthenticator
构造函数外Q还必须配置 authenticator
bean 的两个属性(清单 5 中的两个 <property>
标记Q?/p>
<property>
标记定义了一?userDnPatterns
属性,它封装了一个或多个 DN 模式列表?em>DN 模式 指定了一l具有类似特性的 LDAP 节点Q例??2 所C的 employees
节点的所有子节点Q?/p>
authenticator
bean ?userDnPatterns
属性中配置的每?DN 模式构造了一?DN。例如,查看 清单 5 中配|的W一个模式,?uid={0},ou=employees,ou=partners
。在q行w䆾验证的时候,authenticator
bean 使用用户提供的用户名Q比?alice
Q替换了 {0}
。用用户名取代?{0}
之后QDN 模式变为相?DNQRDNQ?code>uid=alice,ou=employees,ou=partnersQ它需要一个初始上下文才能成ؓ DN?/p>
alice's
条目。该条目?employees
节点的第一个子节点。它?DN ?uid=alice,ou=employees,ou=partners,o=manufacturingEnterprise, dc=org
。如果?o=manufacturingEnterprise,dc=org
作ؓ初始上下文ƈ其d?RDN uid=alice,ou=employees,ou=partners
之后Q将获得 alice ?DN?/p>
authenticator
把 DN 和用户密码发送到 LDAP 目录。目录将查该 DN 是否h正确的密码。如果有的话Q用户就可以通过w䆾验证。这个过E在 LDAP 术语中被UCؓ bind w䆾验证。LDAP q提供了其他cd的n份验证机Ӟ但是本文的示例只使用?bind w䆾验证?/p>
authenticator
bean 尝试所有的 DN 模式来ؓq行w䆾验证的用h造正的用户 DN?/p>
departments
节点内创Z个特定用PspecialUser
Q?/p>
authenticator
bean 不能够构造正的 DNQ从而无法对该用戯行n份验证?/p>
<property>
标记h一?<ref>
子标讎ͼ它引用名?userSearch
?bean?code>userSearch bean 指定搜烦查询。清?6 展示了如何配|?userSearch
bean 来处理特定用P
清单 6. 配置搜烦查询以搜索特定用?/strong>
<bean id="userSearch"
class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg>
<value>ou=departments</value>
</constructor-arg>
<constructor-arg>
<value>(uid={0})</value>
</constructor-arg>
<constructor-arg>
<ref local="initialDirContextFactory" />
</constructor-arg>
<property name="searchSubtree">
<value>true</value>
</property>
</bean>
清单 6 展示?userSearch
bean ?org.acegisecurity.ldap.search.FilterBasedLdapUserSearch
cȝ一个实例,该类的构造函数具有三个参数。第一个参数指?authenticator
在哪个节点中搜烦用户。第一个参数的gؓ ou=departments
Q该值是一?RDNQ指定了 ?2 所C的 departments
节点?/p>
(uid={0})
指定了一个搜索过滤器。由于?uid
属性指定用P因此可以通过查找 uid
属性具有特定值的节点来查扄戗正如您所料,花括号里面的 0 ?Acegi 表示使用q行w䆾验证的用L用户名(本例中ؓ specialUser
Q替?{0}
?BindAuthenticator
构造函数时引入的相同初始上下文的引用。回想一下,当指定了初始上下文后Q稍后将在该初始上下文节点的子节点内q行所有的搜烦操作。注意,应将指定?清单 5 中第一个参敎ͼou=departments
Q的值的 RDN 前加到初始上下文?/p>
userSearch
bean q具有一个名?searchSubtree
的属性。如果将其值指定ؓ true
Q搜索操作将包括节点的子树(x有子节点、孙节点、孙节点的子节点{)Q该节点被指定ؓ构造函数的W一个参数的倹{?authenticator
bean 的配|完成后Q下一步将查看 populator
bean 的配|,?清单 4 所C?/p>
回页?/strong>
populator
bean 读取已l通过 authenticator
bean w䆾验证的用L业务角色。清?7 展示 populator
bean ?XML 配置Q?/p>
清单 7. populator bean ?XML 配置
<bean id="populator"
class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
<constructor-arg>
<ref local="initialDirContextFactory"/>
</constructor-arg>
<constructor-arg>
<value>ou=departments</value>
</constructor-arg>
<property name="groupRoleAttribute">
<value>ou</value>
</property>
<property name="searchSubtree">
<value>true</value>
</property>
</bean>
populator
bean 的构造函数包?2 个参敎ͼ以及一?groupRoleAttribute
属性。构造函数的W一个参数指定了 populator
bean 用来dl过验证用户的业务角色的初始上下文。ƈ不强制要?authenticator
?populator
bean 使用相同的初始上下文。您可以两者分别配|一个初始上下文?/p>
departments
节点?/p>
populator
bean ?groupRoleAttribute
属性指定了持有l成员业务角色数据的属性。回?讄 LDAP 目录 一节中Q您每l用L业务角色信息存储在名?ou
的属性中。然后将 ou
讄?groupRoleAttribute
属性的|?清单 7 所C?populator
bean 搜索整?LDAP 目录来查扄q验证的用户所属的l节炏V然后读取组节点?ou
属性的|获取用户l过授权的业务角艌Ӏ?/p>
populator
bean 的配|。目前ؓ止,我们在三个位|用了初始上下文:清单 5?a cmimpressionsent="1">清单 6 ?清单 7。接下来了解如何配|初始上下文?/p>
清单 8. 初始上下文的 XML 配置
<bean id="initialDirContextFactory"
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
<constructor-arg value="ldap://localhost:389/o=manufacturingEnterprise,dc=org"/>
<property name="managerDn">
<value>cn=manager,o=manufacturingEnterprise,dc=org</value>
</property>
<property name="managerPassword">
<value>secret</value>
</property>
</bean>
org.acegisecurity.ldap.DefaultInitialDirContextFactory
Q这?Acegi 包含的工厂类。Acegi 在内部用该cL造其他处理目录操作(例如在整个目录中搜烦Q的cȝ对象。当配置初始上下文工厂时Q必L定以下内容:
search
Q都在根节点定义的子树中执行?br />
managerDn
?managerPassword
属性。在执行M搜烦操作之前QAcegi 必须使用目录服务器对 DN 和密码进行n份验证?
回页?/strong>
?5. APF 对一?LDAP 用户q行w䆾验证
authenticator
bean?br />
authenticator
用在 清单 5 ?userDnPatterns
属性中配置?DN 模式创徏用户 DN。通过从一?DN 模式中创Z?DNQ然后将?DN 和用户密码(从用戯求中获得Q发送到 LDAP 目录Q它逐一试所有可用的 DN 模式。LDAP 目录检查该 DN 是否存在以及密码是否正确。如果其中Q何一?DN 模式可行的话Q用戯l定?LDAP 目录中,authenticator
l执行步?15?
authenticator
Ҏ 清单 6 配置的搜索查询在 LDAP 目录中搜索用戗如?LDAP 目录没有扑ֈ用户Q那么n份验证以p|告终?br />
authenticator
?br />
authenticator
用?DN 和密码发送到 LDAP 目录来检查用户密码是否正。如?LDAP 目录发现用户密码是正的Q该用户被l定?LDAP 目录?br />
authenticator
用户信息发送回 LDAP w䆾验证提供者?br />
populator
bean?br />
populator
搜烦用户所属的l?br />
populator
?br />
populator
用戯色信息返回给 LDAP w䆾验证提供者?br />
清单 9. 配置拦截qo?/strong>
<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/engineering/**=ROLE_HEAD_OF_ENGINEERING
/protected/marketing/**=ROLE_HEAD_OF_MARKETING
/**=IS_AUTHENTICATED_ANONYMOUSLY
</value>
</property>
</bean>
accessDecisionManager
?beanQ?/p>
accessDecisionManager
bean 负责指定授权决策。它使用清单 9 中第三个参数提供的访问控制定义来指定授权Q或讉K控制Q决{。第三个参数?objectDefinitionSource
?/p>
accessDecisionManager
军_是否允许一个用戯问某个资源。Acegi 提供了一些访问决{管理器Q它们指定访问控制决{的方式有所不同。本文只解释了其中一U访问决{管理器的工作方式,光|如清单 10 所C:
清单 10. 配置讉K决策理?/strong>
<bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter" />
</list>
</property>
</bean>
accessDecisionManager
bean ?org.acegisecurity.vote.AffirmativeBased
cȝ实例?code>accessDecisionManager bean 只包含一个参敎ͼ?em>投票者(voterQ?/em>列表?/p>
accessDecisionManager
查询Ӟ投票者具有三个选项Q允许访问(access-grantedQ、拒l访问(access-deniedQ,如果不确定的话则攑ּ投票Qabstain from votingQ?/p>
AffirmativeBased
讉K决策理器实C单的决策逻辑Q如果Q何投者强制执行肯定投,允许用戯问所h的资源?/p>
objectDefinitionSource
对象传递给投票者。本文的CZ使用了两U类型的投票者,RoleVoter
?AuthenticatedVoter
Q如清单 10 所C。现在看一下每U投者的逻辑Q?/p>
objectDefinitionSource
对象的行中找C ROLE_
前缀开头的角色时才q行投票。如?RoleVoter
没有扑ֈq样的行Q将攑ּ投票Q如果在用户业务角色中找C个匹配的角色Q它投给允许讉KQ如果没有找到匹配的角色Q则投票l拒l访问。在 清单 9 中,有两个角色具?ROLE_
前缀Q?code>ROLE_HEAD_OF_ENGINEERING ?ROLE_HEAD_OF_MARKETING
?br />
objectDefinitionSource
对象中找到具有某个预定义角色的行时才q行投票。在 清单 9 中,有这样一行:IS_AUTHENTICATED_ANONYMOUSLY
。匿名n份验证意味着用户不能够进行n份验证。找到该行后Q?code>AuthenticatedVoter 检查一个匿名n份验证的用户是否可以讉K某些不受保护的资源(卌些资源没有包含在具备 ROLE_
前缀的行中)。如?AuthenticatedVoter
发现所h的资源是不受保护的ƈ?objectDefinitionSource
对象允许匿名w䆾验证的用戯问不受保护的资源Q它投给允许讉KQ否则就投票l拒l访问?
回页?/strong>
alice
查看设计文Qƈ允许用户 bob
查看销售文。它q允许特定用户同时查看设计和销售文。所有这些内定w是在本文开头配|?LDAP 目录服务器时讄的。立?下蝲CZ应用E序 来开始用它?/p>
回页?/strong>
来自:http://www.cnblogs.com/amboyna/archive/2008/03/25/1122084.html
q䆾共分三部分的pd文章介绍?Acegi 安全pȝQAcegi Security SystemQ,它是用于 Java™ 企业应用E序的强大的开源安全框架。在W一文章中QBilal Siddiqui N向您介l?Acegi 的架构和lgQƈ展示如何使用它来保护一个简单的 Java 企业应用E序?/blockquote>
回页?/strong>
回页?/strong>
清单 1. Spring 配置文g的结?/strong>
<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>
<beans>
标记Q它装了一些其他的 <bean>
标记。所有的 Acegi lgQ即qo器、管理器、提供者等Q实际上都是 JavaBean。XML 配置文g中的每个 <bean>
标记都代表一?Acegi lg?/p>
首先注意到的是每个 <bean>
标记都包含一?class 属性,q个属性标识组件所使用的类?code><bean> 标记q具有一?id 属性,它标识作?Acegi lg工作的实例(Java 对象Q?/p>
<bean>
标记标识了名?filterChainProxy
的组件实例,它是名ؓ org.acegisecurity.util.FilterChainProxy
的类的实例?/p>
<bean>
标记的子标记来表C?bean 的依赖关pR比如,注意W一?<bean>
标记?<property>
子标记?code><property> 子标记定义了 <bean>
标记依赖的其?bean 或倹{?/p>
<bean>
标记?<property>
子标记具有一?name 属性和一?<value>
子标讎ͼ分别定义了这?bean 依赖的属性的名称和倹{?/p>
<bean>
标记定义了一个过滤器 bean 依赖于一个管理器 bean。第二个 <bean>
标记表示qo?beanQ而第三个 <bean>
标记表示理?bean?/p>
<bean>
标记包含一?<property>
子标讎ͼ该子标记h两个属性:name
?ref
?code>name 属性定义了qo?bean 的属性,?ref
属性引用了理?bean 的实例(名称Q?/p>
回页?/strong>
清单 2. 配置 SIF
<bean id="httpSessionContextIntegrationFilter"
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>
Authentication
对象中?/p>
Authentication
对象保存?SIF 之前创徏的安全上下文中。存储在安全上下文中?Authentication
对象用于做出授权决{?/p>
清单 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>
<property>
标记配置的?/p>
清单 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>
清单 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>
authenticationEntryPoint
?accessDeniedHandler
?code>authenticationEntryPoint 属性指定登录页面,?accessDeniedHandler
指定 Access Denied 面?/p>
首先看一?清单 6Q它展示了如何定义一个用户及其用戯Ԍ
清单 6. 为用户定义简单的讉K控制{略
alice=123,ROLE_HEAD_OF_ENGINEERING
alice
Q它的密码是 123
Q角色是 ROLE_HEAD_OF_ENGINEERING
。(下一节将说明如何在文件中定义L数量的用户及其用戯Ԍ然后配置拦截qo器以使用q些文g。)
拦截qo器用三个组件来做出授权决策Q我在清?7 中对其进行了配置Q?/p>
清单 7. 配置拦截qo?
<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>
authenticationManager
?code>accessDecisionManager?code>objectDefinitionSourceQ?/p>
authenticationManager
lg与我在介l?Authentication Processing Filter 时讨的n份验证管理器相同。拦截过滤器可以在授权的q程中?authenticationManager
重新对客hq行w䆾验证?br />
accessDecisionManager
lg理授权q程Q这部分内容在本系列的下篇文章中详l讨论?br />
objectDefinitionSource
lg包含对应于将要发生的授权的访问控制定义。例如,清单 7 中的 objectDefinitionSource
属性值包含两?URLQ?code>/protected/* ?/*
Q。其值定义了q些 URL 的角艌Ӏ?code>/protected/* URL 的角色是 ROLE_HEAD_OF_ENGINEERING
。您可以Ҏ应用E序的需要定义Q何角艌Ӏ?br />
回想一?清单 6Q您为用户名 alice
定义?ROLE_HEAD_OF_ENGINEERING
。这是?alice
能够访?/protected/*
URL?
回页?/strong>
?1. 托管 Acegi qo器链以安全地为浏览器客户机服务的容器
?2. SIF 创徏安全上下?/strong>
?3. APF 对用戯行n份验?/strong>
回页?/strong>
?4. 样例应用E序的欢q页面:
web.xml
文gQ如清单 8 所C:
清单 8. 样例应用E序?web.xml 文g
<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>
acegi-config.xml
文g?URL 位于 <context-param>
标记中?br />
<filter>
标记中?br />
<filter-mapping>
标记中。注意:您可以简单地应用程序的所?URLQ?code>/*Q映到 Acegi qo器链代理。Acegi 对映射?Acegi qo器链代理上的所?URL 应用安全性?br />
<listener>
标记中,它将加蝲 Spring ?IOC 框架?
webapps
目录中?br />
http://localhost:8080/acegisample/
?/p>
回页?/strong>
回页?/strong>
描述
名字
大小
下蝲Ҏ
本文源代?/th>
j-acegi1.zip
10KB
HTTP
关于下蝲Ҏ的信?/a>
学习
获得产品和技?/strong>
讨论
来自:http://www.cnblogs.com/amboyna/archive/2008/03/25/1122079.html
]]>
对于M一个完整的应用pȝQ完善的认证和授权机制是必不可少的。在ZSpringFramework的WEB应用中,
我们可以使用Acegi作ؓ安全架构的实现。本文将介绍如何在基于Spring构架的Web应用中用AcegiQƈ且详l介
l如何配|和扩展Acegi框架以适应实际需要?br />
文章和代码下?
http://www.tkk7.com/Files/youlq/Acegi.zip
注意Q许多朋友在部v上遇C些麻烦,所以我可以部|的完整的war文g传上来,注意Qjava代码在acegi-sample.war\WEB-INF 目录下,例子需要MysqlQ徏库脚本在acegi-sample.war\db目录下?/font>
acegi-sample.part1.rar
acegi-sample.part2.rar
acegi-sample.part3.rar
acegi-sample.part4.rar
附注Q?br />
有些朋友询问我如何部|文中的例子Q在此再ơ说明一下(文章中已l有提到Q:
Mysql的徏表脚本在db目录?br />
Z减小体积Q已l将WEB-INF\lib下的依赖包删除,误行下载以下包Qƈ拯至WEB-INF\lib下:
spring-1.2.4.jar
acegi-security-0.8.3.jar
aopalliance-1.0.jar
c3p0-0.9.0.jar
commons-logging-1.0.4.jar
ehcache-1.1.jar
log4j-1.2.8.jar
mysql-connector-java-3.1.10-bin.jar
oro-2.0.8.jar
提示Q?br />
acegi-security-0.8.3.jar
aopalliance-1.0.jar
c3p0-0.9.0.jar
commons-logging-1.0.4.jar
ehcache-1.1.jar
log4j-1.2.8.jar
oro-2.0.8.jar
可以在acegi-security-0.8.3.zip所带的acegi-security-sample-contacts-filter.war中找到?br />
spring-1.2.4.jar
mysql-connector-java-3.1.10-bin.jar
要分别到springframework和mysql|站下蝲?/p>
来自:http://www.tkk7.com/youlq/archive/2005/12/06/22678.html
开发者可以通过http://sourceforge.net/projects/acegisecurity或http://acegisecurity.org/下蝲到Acegi官方发布版,比如acegi-security-1.x.zip。图4-4展示了SF中Acegi目的首,它提供了下蝲AcegiQSpring SecurityQ的入口?/p>
?-4 http://sourceforge.net/projects/acegisecurity首页
在单d4-4中的下蝲Q?#8220;Download Acegi Security System for Spring”Q超链接后,开发者进而能够下载到最新的Acegi官方发布包。此Ӟ开发者同时将acegi-security-1.x.zip、acegi-security-1.x-src.zip下蝲到本圎ͼ前者包含了Jar存档和若qAcegi使能应用Q而后者仅仅包含了Acegi目的源代码?/p>
在下载到Acegi官方发布版后Q通过解压acegi-security-1.x.zipQ开发者能够浏览到如图4-5所C的cM内容?/p>
?-5 acegi-security-1.x.zip包含的内?/p>
通常Q大部分Acegi安全性项目仅仅需要用到acegi-security-1.x.jar存档Q这是Acegi的核心包QQ何Acegi使能目都需要用到它。如果项目打采用Java SE 5引入的Annotation注释支持Q则q需要将acegi-security-tiger-1.x.jard到WEB-INF/lib中。如果开发者在使用Acegi提供的容器适配器支持,则还需要将acegi-security-catalina-1.x.jarQ针对TomcatQ、acegi-security-jboss-1.x.jarQ针对JBossQ、acegi-security-jetty-1.x.jarQ针对JettyQ、acegi-security-resin-1.x.jarQ针对ResinQ等Jar存复制到相应的位置Q至于这些Jar包的具体使用Q本书将在第10章详l阐q?/p>
另外Qacegi-security-sample-contacts-filter.war、acegi-security-sample-tutorial.war是两个直接可部v到Java EE容器QTomcat容器Q中的Web应用?/p>
如今QAcegiZ码采用Subversion理。开发者通过如图4-6所C的Web面能够获得Subversion下蝲地址Qhttp://sourceforge.net/svn/?group_id=104215Q?/p>
?-6 获得下蝲AcegiZ码地址的Web面
事实上,AcegiQSpring SecurityQ基代码本n是一个Eclipse Java目Q而且它的构徏、管理工作采用了Maven 1.x/2.xQhttp://maven.apache.org/Q。开发者可以借助Eclipse Subversive插g从Subversion存储源获得Acegi的最新基代码。图4-7展示了Subversive内置的SVN Repository Exploring?/p>
?-7 Subversive插g使用截图
一旦在下蝲完成AcegiQSpring SecurityQ基代码后,开发者将能够持箋监控到Acegi目的最新情况,比如获得Acegi持箋更新的基代码、Acegi官方文Q图4-8展示了相应的使用截图?/p>
?-8 持箋更新AcegiZ?/p>
其一Q开发者可以去订阅acegisecurity-developer@lists.sourceforge.net邮g列表Q图4-9展示了订阅这一邮g列表的入口。Acegi开发团队积极参与到q一邮g列表中,因此开发者从q一邮g列表能够获得Acegi的最新进展?/p>
?-9 订阅Acegi开发者邮件列?/p>
其二QAcegi官方论坛Qhttp://forum.springframework.org/Q,?-10展示了论坛截图?/p>
?-10 Acegi官方论坛
开发者可以通过许多渠道获得一手的Acegi知识、开发和部vl验?/p>
本章围绕AcegiQSpring SecurityQ的认证{略q行了阐qͼ比如Zqo器的设计、与认证源解耦、AcegiSecurityException异常体系{。另外,我们q针对Acegi发布版和Z码的下蝲q行了简要介l?/p>
下章深入到Acegi支持的各U认证机制中?/p>
l http://acegisecurity.org/
l http://sourceforge.net/projects/acegisecurity
l http://www.polarion.org/index.php?page=overview&project=subversive