屬性文件(第 1 部分)存在三大缺陷:
LDAP 針對讀密集型目錄操作優化,支援層次化數據模型,是企業級身份存儲標準。
dc=org (根)
└── o=manufacturingEnterprise (組織)
├── ou=partners (合作夥伴)
│ ├── ou=customers (客戶組)
│ ├── ou=employees (員工組) ← alice, bob
│ └── ou=suppliers (供應商組)
└── ou=departments (部門)
├── ou=engineering (工程部)
│ └── cn=engineers (工程師組) → ou=ROLE_HEAD_OF_ENGINEERING
├── ou=marketing (市場部)
│ └── cn=marketers (市場組) → ou=ROLE_HEAD_OF_MARKETING
└── uid=specialUser (特殊用戶,驗證搜索靈活性)
dc:域組件(根節點)o:組織名稱ou:組織單元(部門/組)同時用作業務角色值uid:用戶 IDmember:groupOfNames 成員屬性<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>
</bean>
使用 JXplorer 導入 ldif 文件,包含完整節點樹與用戶/組/角色數據。
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list><ref local="ldapAuthenticationProvider"/></list>
</property>
</bean>
<bean id="ldapAuthenticationProvider"
class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
<constructor-arg><ref local="authenticator"/></constructor-arg> <!-- 驗證器 -->
<constructor-arg><ref local="populator"/></constructor-arg> <!-- 權限填充器 -->
</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>
用戶輸入 alice → 替換 {0} → 構造相對 DN uid=alice,ou=employees,ou=partners → 加上初始上下文成完整 DN → 發送 Bind 請求驗證密碼。
<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>
解決 specialUser 等不在標準 DN 模式下的用戶驗證問題。
<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>
遍歷用戶所屬組,讀取組節點的 ou 屬性作為角色(如 ROLE_HEAD_OF_ENGINEERING)。
<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>
<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>
<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>
/protected/engineering/** ✅/protected/marketing/** ✅本文構建了 LDAP 目錄設計 → ApacheDS 部署 → Acegi LDAP 提供者鏈配置 → 授權投票決策 完整鏈路。核心設計點:
ou 屬性映射角色,解耦用戶與角色下一部分將展示如何將這套授權體系延伸到 Java 方法級別。