首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Acegi Security 系列第 2 部分:整合 ApacheDS LDAP 實現企業級訪問控制

     編輯:Java 相關知識

為什麼選擇 LDAP 目錄服務器?

屬性文件(第 1 部分)存在三大缺陷:

  1. 性能:千級用戶文本搜索效率極低
  2. 維護:用戶/角色耦合存儲,職位變更需修改多處
  3. 結構:無法表達組織架構(部門/組/用戶層級)

LDAP 針對讀密集型目錄操作優化,支援層次化數據模型,是企業級身份存儲標準。

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 (特殊用戶,驗證搜索靈活性)

關鍵屬性規範(RFC 2256)

  • dc:域組件(根節點)
  • o:組織名稱
  • ou:組織單元(部門/組)同時用作業務角色值
  • uid:用戶 ID
  • member:groupOfNames 成員屬性

ApacheDS 服務器配置

創建根分區 (server.xml)

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

LDIF 批量導入數據

使用 JXplorer 導入 ldif 文件,包含完整節點樹與用戶/組/角色數據。

Acegi LDAP 整合配置全解析

1. 身份驗證管理器

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
  <property name="providers">
    <list><ref local="ldapAuthenticationProvider"/></list>
  </property>
</bean>

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

3. BindAuthenticator 驗證器配置

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

DN 模式與 {0} 佔位符

用戶輸入 alice → 替換 {0} → 構造相對 DN uid=alice,ou=employees,ou=partners → 加上初始上下文成完整 DN → 發送 Bind 請求驗證密碼。

4. FilterBasedLdapUserSearch 兜底搜索

<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 模式下的用戶驗證問題。

5. DefaultLdapAuthoritiesPopulator 權限填充器

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

6. 初始上下文工廠

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

LDAP 認證授權完整流程(23 步)

  1. FilterChainProxy → AuthenticationProcessingFilter (APF)
  2. APF 創建 Authentication Token(用戶名/密碼)
  3. Token → ProviderManager
  4. ProviderManager 選擇 LdapAuthenticationProvider
  5. Provider → UserCacheService(檢查緩存)
  6. 緩存未命中 → LdapAuthenticationProvider
  7. Provider → BindAuthenticator
  8. Authenticator 遍歷 userDnPatterns 構造 DN → Bind 驗證
  9. 若全部失敗 → userSearch 基於 (uid={0}) 遞歸搜索
  10. 搜索到用戶 DN → 再次 Bind 驗證密碼
  11. 驗證成功 → Provider → Populator
  12. Populator 搜索用戶所屬組(ou=departments 子樹)
  13. 讀取組節點 ou 屬性 → 角色集合
  14. 返回用戶詳情含角色 → Provider → APF
  15. APF 存入 SecurityContext → Session
  16. 後續請求 → FilterSecurityInterceptor → AccessDecisionManager
  17. AccessDecisionManager (AffirmativeBased) → RoleVoter/AuthenticatedVoter
  18. RoleVoter 匹配 ROLE_* 前綴角色
  19. AuthenticatedVoter 處理 IS_AUTHENTICATED_ANONYMOUSLY
  20. 任一投票器肯定 → 授權通過

攔截器與訪問決策配置

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

示例應用驗證

  • alice (工程部) → 訪問 /protected/engineering/** ✅
  • bob (市場部) → 訪問 /protected/marketing/** ✅
  • specialUser (特殊用戶) → 同時訪問兩類資源 ✅
  • 匿名用戶 → 僅訪問公開資源 (**) ✅

總結

本文構建了 LDAP 目錄設計 → ApacheDS 部署 → Acegi LDAP 提供者鏈配置 → 授權投票決策 完整鏈路。核心設計點:

  1. BindAuthenticator 多 DN 模式 + 兜底搜索,支援靈活用戶位置
  2. Populator 通過組節點 ou 屬性映射角色,解耦用戶與角色
  3. 初始上下文 統一連接參數,Manager DN 驗證目錄操作權限
  4. AffirmativeBased + RoleVoter 實現聲明式 URL-角色映射

下一部分將展示如何將這套授權體系延伸到 Java 方法級別。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved