使用 Acegi 保护 Java 应用程序,第 2 部分: 使用 LDAP 目录服务器

ldap与Acegi? ----Acegi配置文件解剖 被解剖的acegi配置文件. 博文链接:https://rmn190.iteye.com/blog/175041 立即下载

这期共分三部分的系列文章介绍了如何使用 Acegi 安全系统保护 Java 企业应用程序。在 本系列第一篇文章 中,我介绍了 Acegi 并解释了如何使用安全过滤器实现一个简单的基于 URL 的安全系统。在第二篇文章中,我将讨论 Acegi 的更加高级的应用,首先我将编写一个访问控制策略并将其存储在 ApacheDS 中,ApacheDS 是一个开源的 LDAP 目录服务器。我还将展示配置 Acegi 的方法,使它能够与目录服务器交互并实现您的访问控制策略。本文的结尾提供了一个示例应用程序,它使用 ApacheDS 和 Acegi 实现了一个安全的访问控制策略。

实现访问控制策略通常包含两个步骤:

  1. 将有关用户和用户角色的数据存储在目录服务器中。
  2. 编写安全代码,它将定义有权访问并使用数据的人员。

Acegi 将减轻代码编写的工作,因此在这篇文章中,我将展示如何将用户和用户角色信息存储到 ApacheDS 中,然后实现这些信息的访问控制策略。在该系列的最后一篇文章中,我将展示如何配置 Acegi,实现对 Java 类的安全访问。

您可以在本文的任何位置 下载样例应用程序。参见 参考资料 下载 Acegi、Tomcat 和 ApacheDS,您需要使用它们运行样例代码和示例应用程序。

LDAP 基础知识

轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)可能是最流行的一种定义数据格式的协议,它针对常见的目录操作,例如对存储在目录服务器中的信息执行的读取、编辑、搜索和删除操作。本节将简要解释为什么目录服务器是属性文件存储安全信息的首选,并展示如何在 LDAP 目录中组织和托管用户信息。

为什么要使用目录服务器?

本系列第一部分向您介绍了一种简单的方法,可以将用户信息以属性文件的形式保存起来(参见 第 1 部分,清单 6)。属性文件以文本格式保存用户名、密码和用户角色。对于大多数真实应用程序而言,使用属性文件存储安全信息远远不够。各种各样的理由表明,目录服务器通常都是更好的选择。其中一个原因是,真实的企业应用程序可以被大量用户访问 —— 通常是几千名用户,如果应用程序将其部分功能公开给用户和供应商时更是如此。频繁搜索文本文件中随意存储的信息,这样做的效率并不高,但是目录服务器对这类搜索进行了优化。

第 1 部分的清单 6 中的属性文件演示了另一个原因,该文件组合了用户和角色。在真实的访问控制应用程序中,您通常都需要分别定义和维护用户和角色信息,这样做可以简化用户库的维护。目录服务器为更改或更新用户信息提供了极大的灵活性,例如,反映职位升迁或新聘用人员。参见 参考资料 以了解更多关于目录服务器的使用及其优点的信息。

LDAP 目录设置

如果希望将用户信息存储在一个 LDAP 目录中,您需要理解一些有关目录设置的内容。本文并没有提供对 LDAP 的完整介绍(参见 参考资料),而是介绍了一些在尝试结合使用 Acegi 和 LDAP 目录之前需要了解的基本概念。

LDAP 目录以节点树的形式存储信息,如图 1 所示:


图 1. LDAP 目录的树状结构
图 1. LDAP 目录的树状结构

在图 1 中,根节点的名称为 org。根节点可以封装与不同企业有关的数据。例如,本系列第 1 部分开发的制造业企业被显示为 org 节点的直接子节点。该制造业企业具有两个名为 departments 和 partners 的子节点。

partners 子节点封装了不同类型的合作伙伴。图 1 所示的三个分别为 customers、employees 和 suppliers。注意,这三种类型的合作伙伴其行为与企业系统用户一样。每一种类型的用户所扮演的业务角色不同,因此访问系统的权利也不同。

类似地,departments 节点包含该制造业企业的不同部门的数据 —— 例如 engineering 和 marketing 字节点。每个部门节点还包含一组或多组用户。在 图 1 中,engineers 组是 engineering 部门的子节点。

假设每个部门的子节点表示一组用户。因此,部门节点的子节点具有不同的用户成员。例如,设计部门的所有工程师都是 engineering 部门内 engineers 组的成员。

最后,注意 图 1 中 departments 节点的最后一个子节点。specialUser 是一名用户,而非一组用户。在目录设置中,像 alice 和 bob 之类的用户一般都包含在 partners 节点中。我将这个特殊用户包含在 departments 节点中,以此证明 Acegi 允许用户位于 LADP 目录中任何地点的灵活性。稍后在本文中,您将了解如何配置 Acegi 以应用 specialUser。

使用专有名称

LDAP 使用专有名称(DN)的概念来识别 LDAP 树上特定的节点。每个节点具有惟一的 DN,它包含该节点完整的层次结构信息。例如,图 2 展示了图 1 中的一些节点的 DN:


图 2. LDAP 目录节点的专有名称
图 2. LDAP 目录节点的专有名称

首先,注意图 2 中根节点的 DN。它的 DN 为 dc=org,这是与 org 根节点相关的属性值对。每个节点都有若干个与之相关的属性。dc 属性代表 “domain component” 并由 LDAP RFC 2256 定义(参见 参考资料 中有关官方 RFC 文档的链接),LDAP 目录中的根节点通常表示为一个域组件。

每个 LDAP 属性是由 RFC 定义的。LDAP 允许使用多个属性创建一个 DN,但是本文的示例只使用了以下 4 个属性:

  • dc(域组件)
  • o(组织)
  • ou(组织单元)
  • uid(用户 ID)

示例使用 dc 表示域,用 o 表示组织名称,ou 表示组织的不同单元,而 uid 表示用户。

由于 org 是根节点,其 DN 只需指定自身的名称(dc=org)。比较一下,manufacturingEnterprise 节点的 DN 是 o=manufacturingEnterprise,dc=org。当向下移动节点树时,每个父节点的 DN 被包含在其子节点的 DN 中。

将属性分组

LDAP 将相关的属性类型分到对象类中。例如,名为 organizationalPerson 的对象类所包含的属性定义了在组织内工作的人员(例如,职称、常用名、邮寄地址等等)。

对象类使用继承特性,这意味着 LDAP 定义了基类来保存常用属性。然后子类再对基类进行扩展,使用其定义的属性。LDAP 目录中的单个节点可以使用若干个对象类:本文的示例使用了以下几个对象类:

  • top 对象类是 LDAP 中所有对象类的基类。

  • 当其他对象类都不适合某个对象时,将使用 domain 对象类。它定义了一组属性,任何一个属性都可以用来指定一个对象。其 dc 属性是强制性的。

  • organization 对象类表示组织节点,例如 图 2 中的 manufacturingEnterprise。

  • organizationalUnit 对象类表示组织内的单元,例如 图 1 中的 departments 节点及其子节点。

  • groupOfNames 对象类表示一组名称,例如某部门职员的名称。它具有一个 member 属性,该属性包含一个用户列表。图 1 中所有的组节点(例如 engineers 节点)使用 member 属性指定该组的成员。而且,示例使用 groupOfNames 对象类的 ou(组织单元)属性指定组用户的业务角色。

  • organizationalPerson 对象类表示组织内某个职员(例如 图 1 中的 alice 节点)。

使用 LDAP 服务器

在真实的应用程序中,通常将有关系统用户的大量信息托管在一个 LDAP 目录中。例如,将存储每个用户的用户名、密码、职称、联系方式和工资信息。为简单起见,下面的例子将只向您展示如何保存用户名和密码。

如前所述,示例使用 ApacheDS(一种开源的 LDAP 目录服务器)演示了 Acegi 是如何使用 LDAP 目录的。示例还使用了一个开源的 LDAP 客户机(名为 JXplorer)执行简单的目录操作,例如将信息托管在 ApacheDS 上。参见 参考资料 以下载 ApacheDS、JXplorer 并了解更多有关两者协作的信息。

在 ApacheDS 创建一个根节点

要创建 图 1 所示的节点树,必须首先在 ApacheDS 中创建一个根节点 org。ApacheDS 为此提供了一个 XML 配置文件。XML 配置文件定义了一组可进行配置的 bean,从而根据应用程序的需求定制目录服务器的行为。本文只解释创建根节点所需的配置。

可以在 ApacheDS 安装中的 conf 文件夹找到名为 server.xml 的 XML 配置文件。打开文件后,会发现很多 bean 配置类似于 Acegi 的过滤器配置。查找名为 examplePartitionsConfiguration 的 bean。该 bean 控制 ApacheDS 上的分区。当创建新的根节点时,实际上将在 LDAP 目录上创建一个新的分区。

编辑 examplePartitionConfiguration bean 以创建 org 根节点,如清单 1 所示:


清单 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 >

清单 1 编辑了 examplePartitionConfiguration bean 的两个属性:

  • 一个属性名为 suffix,它定义根条目的 DN。

  • 另一个属性名为 contextEntry,定义 org 节点将使用的对象类。注意,org 根节点使用两个对象类:top 和 domain。

本文的 源代码下载 部分包含了编辑模式的 server.xml 文件。如果希望继续学习本示例,请将 server.xml 文件从源代码中复制到您的 ApacheDS 安装目录中的正确位置,即 conf 文件夹。

图 3 所示的屏幕截图展示了在 ApacheDS 中创建根节点后,JXplorer 是如何显示该根节点的:


图 3. JXplorer 显示根节点
图 3. JXplorer 显示根节点

填充服务器

设置 LDAP 服务器的下一步是使用用户和组信息填充服务器。您可以使用 JXplorer 在 ApacheDS 中逐个创建节点,但是使用 LDAP Data Interchange Format (LDIF) 填充服务器会更加方便。LDIF 是可被大多数 LDAP 实现识别的常见格式。developerWorks 文章很好地介绍了 LDIF 文件的内容,因此本文将不再做详细说明。(参见 参考资料 中有关 LDIF 的详细资料。)

您可以在 源代码下载 部分查看 LDIF 文件,它表示 图 1 所示的用户和部门。您可以使用 JXplorer 将 LDIF 文件导入到 ApacheDS。要导入 LDIF 文件,在 JXplorer 中使用 LDIF 菜单,如图 4 所示:


图 4. 将 LDIF 文件导入到 ApacheDS
图 4. 将 LDIF 文件导入到 ApacheDS

将 LDIF 文件导入到 ApacheDS 之后,JXplorer 将显示用户节点和部门节点树,如 图 1 所示。现在您可以开始配置 Acegi,使其能够与您的 LDAP 服务器通信。

为 LDAP 实现配置 Acegi

回想一下第 1 部分,其中 Acegi 使用身份验证处理过滤器(Authentication Processing Filter,APF)进行身份验证。APF 执行所有后端身份验证处理任务,例如从客户机请求中提取用户名和密码,从后端用户库读取用户参数,以及使用这些信息对用户进行身份验证。

您在第 1 部分中为属性文件实现配置了 APF,现在您已将用户库存储在 LDAP 目录中,因此必须使用不同的方式配置过滤器来和 LDAP 目录进行通信。首先看一下清单 2,它展示了在第 1 部分中的 “Authentication Processing Filter” 一节中如何为属性文件实现配置 APF 过滤器:


清单 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 >

查看一下清单 2,您曾经为 APF 提供了 4 个参数。您只需在 LDAP 服务器中为存储重新配置第一个参数(authenticationManager)即可。其他三个参数保持不变。

配置身份验证管理器

清单 3 展示了如何配置 Acegi 的身份验证管理器,以实现与 LDAP 服务器的通信:


清单 3. 为 LDAP 配置 Acegi 的身份验证管理器

< bean  id ="authenticationManager"
class
="org.acegisecurity.providers.ProviderManager" >

< property  name ="providers" >
< list >
< ref  local ="ldapAuthenticationProvider"   />
</ list >
</ property >

</ bean >

在清单 3 中,org.acegisecurity.providers.ProviderManager 是一个管理器类,它管理 Acegi 的身份验证过程。为此,身份验证管理器需要一个或多个身份验证提供者。您可以使用管理器 bean 的提供者属性来配置一个或多个提供者。清单 3 只包含了一个提供者,即 LDAP 身份验证提供者。

LDAP 身份验证提供者处理所有与后端 LDAP 目录的通信。您必须对其进行配置,下一节内容将讨论该主题。

配置 LDAP 身份验证提供者

清单 4 展示了 LDAP 身份验证提供者的配置:


清单 4. 配置 LDAP 身份验证提供者

< bean  id ="ldapAuthenticationProvider"
class
="org.acegisecurity.providers.ldap.LdapAuthenticationProvider" >

< constructor-arg >< ref  local ="authenticator" /></ constructor-arg >

< constructor-arg >< ref  local ="populator" /></ constructor-arg >

</ bean >

注意 LDAP 身份验证提供者类的名称为 org.acegisecurity.providers.ldap.LdapAuthenticationProvider 。其构造函数包含两个参数,使用两个 <constructor-arg> 标记的形式,如清单 4 所示。

LdapAuthenticationProvider 构造函数的第一个参数是 authenticator,该参数通过检查用户的用户名和密码对 LDAP 目录的用户进行身份验证。完成身份验证后,第二个参数 populator 将从 LDAP 目录中检索有关该用户的访问权限(或业务角色)信息。

以下小节将向您展示如何配置验证器和填充器 bean。

配置验证器

authenticator bean 将检查具有给定用户名和密码的用户是否存在于 LDAP 目录中。Acegi 提供了名为 org.acegisecurity.providers.ldap.authenticator.BindAuthenticator 的验证器类,它将执行验证用户名和密码所需的功能。

配置 authenticator bean,如清单 5 所示:


清单 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 >

在清单 5 中,BindAuthenticator 构造函数具有一个参数,使用 <constructor-arg> 标记的形式。清单 5 中参数的名称为 initialDirContextFactory。该参数实际上是另一个 bean,稍后您将学习如何配置该 bean。

目前为止,只知道 initialDirContextFactory bean 的作用就是为稍后的搜索操作指定初始上下文。初始上下文是一个 DN,它指定了 LDAP 目录内某个节点。指定初始上下文后,将在该节点的子节点中执行所有的搜索操作(例如查找特定用户)。

例如,回到 图 2 中查看 partners 节点,它的 DN 是 ou=partners,o=manufacturingEnterprise,dc=org。如果将 partners 节点指定为初始上下文,Acegi 将只在 partners 节点的子节点中查找用户。

指定 DN 模式

除配置 BindAuthenticator 构造函数外,还必须配置 authenticator bean 的两个属性(清单 5 中的两个 <property> 标记)。

第一个 <property> 标记定义了一个 userDnPatterns 属性,它封装了一个或多个 DN 模式列表。DN 模式 指定了一组具有类似特性的 LDAP 节点(例如 图 2 所示的 employees 节点的所有子节点)。

Acegi 的身份验证器从 authenticator bean 的 userDnPatterns 属性中配置的每个 DN 模式构造了一个 DN。例如,查看 清单 5 中配置的第一个模式,即 uid={0},ou=employees,ou=partners。在进行身份验证的时候,authenticator bean 使用用户提供的用户名(比如 alice)替换了 {0}。使用用户名取代了 {0} 之后,DN 模式将变为相对 DN(RDN)uid=alice,ou=employees,ou=partners,它需要一个初始上下文才能成为 DN。

例如,查看 图 2 中的 alice's 条目。该条目是 employees 节点的第一个子节点。它的 DN 是 uid=alice,ou=employees,ou=partners,o=manufacturingEnterprise, dc=org。如果使用 o=manufacturingEnterprise,dc=org 作为初始上下文并将其添加到 RDN uid=alice,ou=employees,ou=partners 之后,将获得 alice 的 DN。

使用这种方法通过 DN 模式构建了用户的 DN 后,authenticator 将把 DN 和用户密码发送到 LDAP 目录。目录将检查该 DN 是否具有正确的密码。如果有的话,用户就可以通过身份验证。这个过程在 LDAP 术语中被称为 bind 身份验证。LDAP 还提供了其他类型的身份验证机制,但是本文的示例只使用了 bind 身份验证。

如果目录中并没有第一个 DN 模式创建的 DN,authenticator bean 尝试使用列表中配置的第二个 DN 模式。依此类推,authenticator bean 将尝试所有的 DN 模式来为进行身份验证的用户构造正确的用户 DN。

搜索过滤器

回想一下较早的章节 “LDAP 目录设置”,我在将用户信息存储到 LDAP 目录时添加了一点灵活性。方法是在 图 1 所示的 departments 节点内创建一个特定用户(specialUser)。

如果试图使用 清单 5 中配置的任何一种 DN 模式创建特定用户的 DN,您会发现没有一种 DN 模式可用。因此,当用户尝试登录时,Acegi 的 authenticator bean 将不能够构造正确的 DN,从而无法对该用户进行身份验证。

通过允许您指定搜索过滤器,Acegi 能够处理类似的特殊情况。身份验证器 bean 使用搜索过滤器查找不能够通过 DN 模式构造 DN 进行身份验证的用户。

清单 5 中的第二个 <property> 标记具有一个 <ref> 子标记,它引用名为 userSearch 的 bean。userSearch bean 指定搜索查询。清单 6 展示了如何配置 userSearch bean 来处理特定用户:


清单 6. 配置搜索查询以搜索特定用户

< 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 类的一个实例,该类的构造函数具有三个参数。第一个参数指定 authenticator 在哪个节点中搜索用户。第一个参数的值为 ou=departments,该值是一个 RDN,指定了 图 2 所示的 departments 节点。

第二个参数 (uid={0}) 指定了一个搜索过滤器。由于使用 uid 属性指定用户,因此可以通过查找 uid 属性具有特定值的节点来查找用户。正如您所料,花括号里面的 0 向 Acegi 表示使用进行身份验证的用户的用户名(本例中为 specialUser)替换 {0}。

第三个参数是对讨论 清单 5 中的 BindAuthenticator 构造函数时引入的相同初始上下文的引用。回想一下,当指定了初始上下文后,稍后将在该初始上下文节点的子节点内进行所有的搜索操作。注意,应将指定为 清单 5 中第一个参数(ou=departments)的值的 RDN 前加到初始上下文。

除了这三个构造器参数,清单 6 所示的 userSearch bean 还具有一个名为 searchSubtree 的属性。如果将其值指定为 true,搜索操作将包括节点的子树(即所有子节点、孙节点、孙节点的子节点等),该节点被指定为构造函数的第一个参数的值。

authenticator bean 的配置完成后,下一步将查看 populator bean 的配置,如 清单 4 所示。

配置 populator

populator bean 将读取已经通过 authenticator bean 身份验证的用户的业务角色。清单 7 展示 populator bean 的 XML 配置:


清单 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 >

在清单 7 中,populator bean 的构造函数包括 2 个参数,以及一个 groupRoleAttribute 属性。构造函数的第一个参数指定了 populator bean 用来读取经过验证用户的业务角色的初始上下文。并不强制要求 authenticator 和 populator bean 使用相同的初始上下文。您可以为这两者分别配置一个初始上下文。

第二个构造函数参数指定了 populator 前加到初始上下文的 RDN。因此,RDN 组成了包含组用户的节点的 DN,例如 departments 节点。

populator bean 的 groupRoleAttribute 属性指定了持有组成员业务角色数据的属性。回想 设置 LDAP 目录 一节中,您将每组用户的业务角色信息存储在名为 ou 的属性中。然后将 ou 设置为 groupRoleAttribute 属性的值,如 清单 7 所示。

如您所料,populator bean 将搜索整个 LDAP 目录来查找经过验证的用户所属的组节点。然后读取组节点的 ou 属性的值,获取用户经过授权的业务角色。

这样就完成了 populator bean 的配置。目前为止,我们在三个位置使用了初始上下文:清单 5、清单 6 和 清单 7。接下来将了解如何配置初始上下文。

配置初始上下文

清单 8 展示了在 Acegi 中配置初始上下文的过程:


清单 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 >

清单 8 中 Acegi 的初始上下文类的名称为 org.acegisecurity.ldap.DefaultInitialDirContextFactory,这是 Acegi 包含的工厂类。Acegi 在内部使用该类构造其他处理目录操作(例如在整个目录中搜索)的类的对象。当配置初始上下文工厂时,必须指定以下内容:

  • 将您的 LDAP 目录和根目录节点的网络地址指定为构造函数的参数。在初始上下文配置的节点将作为根节点。就是说所有后续操作(例如 search)都将在根节点定义的子树中执行。

  • 将 DN 和密码分别定义为 managerDn 和 managerPassword 属性。在执行任何搜索操作之前,Acegi 必须使用目录服务器对 DN 和密码进行身份验证。

您已经了解了如何将用户库托管在 LDAP 目录中,以及如何配置 Acegi 来使用来自 LDAP 目录的信息对用户进行身份验证。下一节将进一步介绍 Acegi 的身份验证处理过滤器,了解新配置的 bean 是如何管理身份验证过程的。

身份验证和授权

APF 配置完成后,将能够与 LDAP 目录进行通信来对用户进行身份验证。如果您阅读过第 1 部分,那么对与目录通信过程中 APF 执行的一些步骤不会感到陌生,我在第 1 部分中向您展示了过滤器如何使用不同的服务进行用户身份验证。图 5 所示的序列表与您在 第 1 部分图 3 看到的非常类似:


图 5. APF 对一名 LDAP 用户进行身份验证
图 5. APF 对一名 LDAP 用户进行身份验证

无论 APF 使用属性文件进行内部的身份验证还是与 LDAP 服务器进行通信,步骤 1 到步骤 9 与第 1 部分是相同的。这里简单描述了前 9 个步骤,您可以从步骤 10 开始继续学习特定于 LDAP 的事件:

  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. 从这里开始,身份验证处理将特定于 LDAP。 如果缓存返回 null,LDAP 身份验证提供者将把用户名(在步骤 6 中提取的)和密码传递给 清单 5 中配置的 authenticator bean。

  11. authenticator 将使用在 清单 5 的 userDnPatterns 属性中配置的 DN 模式创建用户 DN。通过从一个 DN 模式中创建一个 DN,然后将该 DN 和用户密码(从用户请求中获得)发送到 LDAP 目录,它将逐一尝试所有可用的 DN 模式。LDAP 目录将检查该 DN 是否存在以及密码是否正确。如果其中任何一个 DN 模式可行的话,用户被绑定到 LDAP 目录中,authenticator 将继续执行步骤 15。

  12. 如果任何一种 DN 模式都不能工作的话(这意味着在 DN 模式指定的任何位置都不存在使用给定密码的用户),authenticator 根据 清单 6 配置的搜索查询在 LDAP 目录中搜索用户。如果 LDAP 目录没有找到用户,那么身份验证以失败告终。

  13. 如果 LDAP 目录查找到了用户,它将用户的 DN 返回到 authenticator。

  14. authenticator 将用户 DN 和密码发送到 LDAP 目录来检查用户密码是否正确。如果 LDAP 目录发现用户密码是正确的,该用户将被绑定到 LDAP 目录。

  15. authenticator 将用户信息发送回 LDAP 身份验证提供者。

  16. LDAP 身份验证提供者将控制权传递给 populator bean。

  17. populator 搜索用户所属的组。

  18. LDAP 目录将用户角色信息返回给 populator。

  19. populator 将用户角色信息返回给 LDAP 身份验证提供者。

  20. LDAP 身份验证提供者将用户的详细信息(以及用户业务角色信息)返回给 APF。用户现在成功进行了身份验证。

不论使用何种身份验证方法,最后三个步骤是相同的(步骤21、21 和 23)。

配置拦截器

您已经了解了 APF 对用户进行身份验证的步骤。接下来是查看成功进行身份验证的用户是否被授权访问所请求的资源。这项任务由 Acegi 的拦截过滤器(Interceptor Filter,IF)完成。本节将向您展示如何配置 IF 来实现访问控制策略。

回想一下在 第 1 部分的清单 7 中配置 IF 的步骤。拦截过滤器在资源和角色之间建立映射,就是说只有具备必要角色的用户才能访问给定资源。为了演示制造业企业中不同部门的业务角色,清单 9 向现有的 IF 配置添加了另外的角色:


清单 9. 配置拦截过滤器

< 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 >

在清单 9 中,IF 包含三个参数。其中第一个和第三个参数与第 1 部分中最初配置的参数相同。这里添加了第二个参数(名为 accessDecisionManager 的 bean)。

accessDecisionManager bean 负责指定授权决策。它使用清单 9 中第三个参数提供的访问控制定义来指定授权(或访问控制)决策。第三个参数是 objectDefinitionSource。

配置访问决策管理器

accessDecisionManager 决定是否允许一个用户访问某个资源。Acegi 提供了一些访问决策管理器,它们指定访问控制决策的方式有所不同。本文只解释了其中一种访问决策管理器的工作方式,其配置如清单 10 所示:


清单 10. 配置访问决策管理器
< 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 >

在清单 10 中,accessDecisionManager bean 是 org.acegisecurity.vote.AffirmativeBased 类的实例。accessDecisionManager bean 只包含一个参数,即投票者(voter)列表。

在 Acegi 中,投票者确定是否允许某个用户访问特定的资源。当使用 accessDecisionManager 查询时,投票者具有三个选项:允许访问(access-granted)、拒绝访问(access-denied),如果不确定的话则放弃投票(abstain from voting)。

不同类型的访问决策管理器解释投票者决策的方法也有所不同。清单 10 所示的 AffirmativeBased 访问决策管理器实现了简单的决策逻辑:如果任何投票者强制执行肯定投票,将允许用户访问所请求的资源。

投票者逻辑

Acegi 提供了若干个投票者实现类型。accessDecisionManager 将经过验证的用户的信息(包括用户的业务角色信息)和 objectDefinitionSource 对象传递给投票者。本文的示例使用了两种类型的投票者,RoleVoter 和 AuthenticatedVoter,如清单 10 所示。现在看一下每种投票者的逻辑:

  • RoleVoter 只有在 objectDefinitionSource 对象的行中找到以 ROLE_ 前缀开头的角色时才进行投票。如果 RoleVoter 没有找到这样的行,将放弃投票;如果在用户业务角色中找到一个匹配的角色,它将投票给允许访问;如果没有找到匹配的角色,则投票给拒绝访问。在 清单 9 中,有两个角色具有 ROLE_ 前缀:ROLE_HEAD_OF_ENGINEERING 和 ROLE_HEAD_OF_MARKETING。

  • AuthenticatedVoter 只有在 objectDefinitionSource 对象中找到具有某个预定义角色的行时才进行投票。在 清单 9 中,有这样一行:IS_AUTHENTICATED_ANONYMOUSLY。匿名身份验证意味着用户不能够进行身份验证。找到该行后,AuthenticatedVoter 将检查一个匿名身份验证的用户是否可以访问某些不受保护的资源(即这些资源没有包含在具备 ROLE_ 前缀的行中)。如果 AuthenticatedVoter 发现所请求的资源是不受保护的并且 objectDefinitionSource 对象允许匿名身份验证的用户访问不受保护的资源,它将投票给允许访问;否则就投票给拒绝访问。

示例应用程序

本文提供了一个示例应用程序,它将演示您目前掌握的 LDAP 和 Acegi 概念。LDAP-Acegi 应用程序将显示一个索引页面,该页面将设计和销售文档呈现给合适的经过身份验证的用户。正如您将看到的一样,LDAP-Acegi 应用程序允许用户 alice 查看设计文档,并允许用户 bob 查看销售文档。它还允许特定用户同时查看设计和销售文档。所有这些内容都是在本文开头配置 LDAP 目录服务器时设置的。立即 下载示例应用程序 来开始使用它。

结束语

在本文中,您了解了如何将用户和业务角色信息托管在 LDAP 目录中。您还详细了解了配置 Acegi 的方法,从而与 LDAP 目录交互实现访问控制策略。在本系列最后一期文章中,我将展示如何配置 Acegi 来保护对 Java 类的访问。

下载

描述名字大小下载方法
本文源代码j-acegi2.zip10KBHTTP
关于下载方法的信息


参考资料

学习

STM32_WS2811驱动 STM32的WS2811驱动 阅读详情

相关推荐

过压保护电路(OVP)

作者:AirCity 2020.2.4 Aircity007@sina.com 本文所有权归作者Aircity所有 1 示例一 当VBUS=5V时,各点电压电流如图所示,Q1接近截止,输出信号是5V。 当VBUS=5.4V开始,输出信号开始下降,直到VBUS=6.1V,输出信号降低为0.6V。 下面是实测波形,这个电路,输出信号的电压不会超过5.4V,这个输出信号可用于电源的控制信号。 2 ...

AirCity123的博客 3万+

Spring Security Ldap 登录认证流程的源码梳理

Spring Security Ldap的登录认证流程源码分析

gelong_bokewang的博客 2013

kemeas算法继续优化——elkan kmeas算法

题记:又是凌晨3点的夜 elkan kmeans算法 在我的上一篇博客《kmeans算法性能改进_kmeans++算法+kmeans++优化算法+距离计算优化》中,在一般kmeans算法的基础上,添加了对于初始条件和距离计算更上的一些优化技巧。这篇博客聊一聊elkan算法,其实也是对于kmeans运行速度的优化算法。主要作用与kmeans的距离计算过程。 原理 假如我们已经知道任意两个样本之间的距离,再假设我们已经知道了样本1与聚类中心1之间的距离,根据三角性两边之和大于第三边,c+d>a,所以如果

铁血军的小博客 7065

Spring Security进阶——集成LDAP认证

如果对于这系列文章有疑问,可以先阅读以下链接内容(含Demo及源码下载):  Spring Security入门篇——搭建简易权限框架:http://www.javali.org/archive/getting-start-spring-security.html  Spring Security入门篇——集成DB认证:http://www.javali.org/archive/getti

wei_ya_wen的专栏 7931

机器视觉避坑指南:为什么你的Halcon划痕检测总漏检?(附优化方案)

本文深入剖析了Halcon在表面划痕检测中漏检率高的常见原因,如灰度值波动、噪声干扰及形态学参数设置不当。针对复杂背景与低对比度划痕,提出了超越官方例程的多尺度纹理分析与特征融合优化方案,旨在帮助开发者构建更鲁棒、稳定的机器视觉检测流程,有效提升检出率。

weixin_29057163的博客 235

【YOLOv8系列】YOLOv8的webUI界面设计;通过Streamlit实现YOLOv8的可视化交互界面设计

但是我为了避免重复性的工作,且为了避免重复安装之前(安装pytorch和yolov8时)已经安装好的库,因此写了一个python脚本进行安装;需要提前在有网络连接的电脑上下载所有必要的依赖项,然后将这些文件传输到离线的机器上进行安装。脚本将自动跳过已安装的包,并安装其余的 .whl 文件。在离线的机器上,切换到包含下载好的文件的目录。证明我们的streamlit安装成功了。证明你的streamlit安装成功了。第一步:在有网络连接的电脑上下载。第二步:将下载的文件传输到离线机器。文件)传输到离线的机器上。

AnChenliang_1002的博客 1567

验证用户身份 -《Spring in Action(第二版)中文版》

原文http://coral9527.blog.sohu.com/157500690.html 7.2 验证用户身份 在为应用程序应用安全措施时,决定是否允许用户访问受保护资源之前首先需要判断用户的身份。在绝大多数应用程序中,这意味着为用户显示一个登录界面,并要求他们提供用户名和密码。 不同应用程序提示用户输入其用户名和密码的方式有所不同。现在,我们假设用户具体的登录信息已经提供,并且需要...

weixin_30674525的博客 250

【反蒸馏实战 00】AI抢不走的工作:一份针对30个“高危”职位的“反取代”实战手册(反蒸馏计划启动)

AI时代职场生存指南:30个技术岗位的“反蒸馏”实战策略 随着AI技术快速发展,职场正面临前所未有的结构性重构。本系列专栏聚焦30个技术岗位,深入分析AI对各职位的影响路径,并提供系统性的"反蒸馏"策略。通过5层分析框架(AI冲击现状、核心价值解构、AI天花板、能力升级路径、人机协作模式),帮助从业者识别可替代任务与核心价值,建立不可替代的专业优势。内容涵盖IT开发、数据分析、产品管理等技术领域,为职场人提供从“被AI替代”到“与AI协同”的转型路线图,守护职业价值。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1651

浅谈Spring Security-Ldap认证配置

最近在项目中使用公司的LDAP做身份认证,积累了一些经验,与大家分享一下。 首选报告一下我们项目的概况,我们的项目是用java开发的,基于 spring 的web应用。主要相关软件或库的版本为: java:1.6,maven:3.0.4,tomcat:7,spring framework:3.2.2.RELEASE,spring security:3.1.3.RELEASE 我的...

乱码人生 891

RK3399快速上手 | 01- 开发环境搭建(固件烧写、编译工具链安装、kernel编译)

一、编译工具链 编译工具链使用gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu。 下载地址: https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/arm-linux-gnueabihf/ wget https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/arm-linux-gnueabi

Mculover666的博客(嵌入式) 8836

MATLAB和S7-1200PLC水箱液位高度PID控制联合仿真(KEPserverOPC通信应用)

SMART PLC 向导PID的详细介绍请查看下面文章链接:S7-200 SMART PLC PID向导详细介绍(如何实现P、PD、PID控制器)-优快云博客文章浏览阅读1k次。这篇博客主要介绍SMART PLC PID向导的使用,PID控制相关的其它内容请查看专栏系列文章,常用链接如下:SMART PLC PID负压控制(过程量为负数)_负压控制pid控制程序_RXXW_Dor的博客-优快云博客1、如何实现PID反作用调节?S7-1200PLC和KEPserver OPC通信-优快云博客。

RXXW_Dor的博客 1781

[转载]使用 Acegi 保护 Java 应用程序,第 2 部分: 使用 LDAP 目录服务器

使用 Acegi 保护 Java 应用程序,第 2 部分: 使用 LDAP 目录服务器2007 年 6 月 21 日了解了 Acegi 安全系统(Acegi Security System)的 基础知识 后,我们将介绍该系...

congji3817的博客 180

【永磁同步电机】simulink永磁同步电机PMSM矢量控制【含Matlab源码 7372期】

simulink永磁同步电机PMSM矢量控制 完整的代码,方可运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 1029

[转]使用 Acegi 保护 Java 应用程序,第 2 部分: 使用 LDAP 目录服务器

使用 ApacheDS 和 Acegi 实现访问控制 ...

weixin_30902251的博客 122

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

使用 Acegi 保护 Java 应用程序

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

466

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

使用 Acegi 保护 Java 应用程序: 续二

使用 Acegi 保护 Java 应用程序: 续二 了解了 Acegi 安全系统(Acegi Security System)的 基础知识 后,我们将介绍该系统的更加高级的应用。在本文中,Bilal Siddiqui 向您展示了如何结合使用 Acegi 和一个 LDAP 目录服务器,实现灵活的具有高性能的 Java™ 应用程序的安全性。还将了解如何编写访问控制策略并将其存储在 ApacheDS 中...

asbss的博客 177

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

使用 Acegi 保护 Java 应用程序,第 3 部分: 实现对 Java 对象的访问控制

这期共分三部分的系列文章介绍了如何使用 Acegi 安全系统保护 Java 企业应用程序。系列文章的 第 1 部分 简单介绍了 Acegi 并解释如何使用其内置的安全过滤器实现一个简单的、基于 URL 的安全系统。第 2 部分 介绍了如何编写访问控制策略并将其保存到一个 LDAP 目录服务器,以及如何配置 Acegi 来与目录服务器进行交互,从而实现访问控制策略。第 3 部分(也是本系列的最后一篇

476

使用 Acegi 保护 Java 应用程序: 续三

本文是 Acegi Security Systerm 介绍的最后一部分(共三部分),Bilal Siddiqui 将向您介绍如何保护对 Java 类实例的访问,从而结束本系列文章。通过本文了解为何需要对 Java™ 类的访问进行保护,Spring 如何创建和保护对 Java 类实例的访问以及如何对 Acegi 进行配置以实现 Java 应用程序的类安全性。这期共分三部分的系列文章介绍了如何使用 A...

asbss的博客 180

[转]使用 Acegi 保护 Java 应用程序,第 4 部分: 保护 JSF 应用程序

针对 JavaServer Faces 应用程序的可配置安全性 ...

weixin_30649859的博客 95

acegi,IBM的Acegi Security System(2)

使用 Acegi 保护 Java 应用程序,第 2 部分: 使用 LDAP 目录服务器 使用 ApacheDS 和 Acegi 实现访问控制 ...

weixin_34167043的博客 107

acegi,IBM的Acegi Security System(3)

使用 Acegi 保护 Java 应用程序,第 3 部分: 实现对 Java 对象的访问控制 使用基于方法的安全性保护 Java 类实例 ...

weixin_30446197的博客 91

acegi,IBM的Acegi Security System(4)

使用 Acegi 保护 Java 应用程序,第 4 部分: 保护 JSF 应用程序 针对 JavaServer Faces 应用程序的可配置安全性 ...

weixin_30947043的博客 62
上一篇: 使用 Acegi 保护 Java 应用程序,第 1 部分: 架构概览和安全过滤器
下一篇: 使用 Acegi 保护 Java 应用程序,第 3 部分: 实现对 Java 对象的访问控制
phantomhu
博客等级 码龄23年 70粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值