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

Acegi Security 系列第 1 部分:架構核心與基於 URL 的安全過濾器鏈

     編輯:Java 相關知識

Acegi Security System 核心價值

企業應用安全痛點:ECM 系統需控制文件系統/數據庫/目錄服務等異構數據源訪問。Acegi 提供聲明式、可配置、無侵入的安全框架,專為 Spring 設計但通用於所有 Java 應用。

開箱即用的安全能力

  • 自動登錄頁面、記住我、會話固定保護
  • 基於角色/表達式的細粒度授權
  • 登出處理、安全上下文傳播、緩存優化
  • 多後端存儲適配(LDAP/JDBC/內存/目錄服務)

四大核心組件體系

組件類型代表職責
Filter (過濾器)AuthenticationProcessingFilter, FilterSecurityInterceptor最高級抽象,處理認證/授權/會話/登出等 HTTP 級關注點
Manager (管理器)ProviderManager, AccessDecisionManager協調多個 Provider/Voter,封裝決策邏輯
Provider (提供者)DaoAuthenticationProvider, LdapAuthenticationProvider對接具體用戶存儲(屬性文件/LDAP/數據庫),執行認證邏輯
Handler (處理器)SecurityContextLogoutHandler, RememberMeServices原子操作步驟(如使會話失效、刪除 Cookie),組合靈活

IOC 與 XML 配置:依賴管理基石

Acegi 組件間依賴複雜,通過 Spring IOC 容器管理:

<beans>
  <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
    <property name="filterInvocationDefinitionSource">
      <value>...URL-過濾器映射...</value>
    </property>
  </bean>
  
  <bean id="authenticationProcessingFilter" 
        class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
    <property name="authenticationManager" ref="authManager"/> <!-- 依賴管理器 -->
  </bean>
  
  <bean id="authManager" class="org.acegisecurity.providers.ProviderManager">
    <property name="providers">
      <list><!-- Provider 列表 --></list>
    </property>
  </bean>
</beans>
  • <bean>:每個 Acegi 組件實例
  • id:實例標識,供 ref 引用
  • class:實現類
  • <property name="..." ref="..."/>:引用其他 Bean 實例(依賴注入)
  • <property name="..." value="..."/>:注入字面值

五大核心安全過濾器詳解

1. HttpSessionContextIntegrationFilter (SIF) —— 安全上下文管理器

  • 位於過濾器鏈最前端
  • 創建 SecurityContext(安全信息占位符)存入 SecurityContextHolder
  • 從 HTTP Session 恢復或創建新上下文
  • 鏈結束時:上下文有變更 → 保存回 Session;無變更 → 刪除上下文

2. AuthenticationProcessingFilter (APF) —— 表單認證處理器

<bean id="authenticationProcessingFilter" 
      class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="filterProcessesUrl" value="/j_acegi_security_check"/> <!-- 登錄提交 URL -->
  <property name="defaultTargetUrl" value="/protected/protected1.jsp"/>   <!-- 登錄成功跳轉 -->
  <property name="authenticationFailureUrl" value="/login.jsp?login_error=1"/> <!-- 失敗跳轉 -->
</bean>
  • 攔截 /j_acegi_security_check POST 請求
  • 提取用戶名/密碼 → 創建 UsernamePasswordAuthenticationToken
  • 委派 AuthenticationManager 驗證 → 成功存入 SecurityContext → 重定向

3. LogoutFilter (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>
  • 攔截登出 URL(默認 /j_acegi_logout)
  • 執行 Handler 列表:SecurityContextLogoutHandler 使 HTTP Session 無效
  • 重定向到成功頁

4. ExceptionTranslationFilter (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>
  • 捕獲鏈中拋出的 AuthenticationException → 重定向到登錄頁
  • 捕獲 AccessDeniedException → 渲染 403 拒絕頁

5. FilterSecurityInterceptor (FSI) —— URL 授權攔截器

<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>
</bean>
  • objectDefinitionSource:Ant 風格 URL 模式 → 角色映射
  • 委派 AccessDecisionManager 決策(見下文)

過濾器鏈生命周期(容器視角)

  1. 瀏覽器發送 HTTP 請求
  2. 容器創建 Request/Response,調用 FilterChainProxy(代理過濾器)
  3. 代理按配置順序調用各過濾器:SIF → APF → LPF → ETF → FSI → ...
  4. 每個過濾器可:處理並調用 chain.doFilter()、直接返回(如 APF 處理登錄)、拋出異常(由 ETF 捕獲)
  5. FSI 執行授權決策
  6. 授權通過 → 轉發給目標資源(JSP/Servlet)
  7. 應用生成響應 → 容器轉為 HTTP 響應返回

SIF 與 APF 內部流程深度解析

SIF 創建 SecurityContext(6 步)

  1. FilterChainProxy 調用 SIF
  2. 檢查請求標記,首次調用則設置標記
  3. 從 Session 獲取 SecurityContext → 放入 SecurityContextHolder;無則創建新上下文
  4. 調用下一個過濾器
  5. 其他過濾器修改上下文(如 APF 存入 Authentication)
  6. 鏈返回 → 檢查上下文是否修改 → 是則保存回 Session,否則刪除

APF 認證流程(14 步)

  1. 前置過濾器傳遞 Request/Response/Chain
  2. 從 Request 提取用戶名/密碼 → 創建 Authentication Token
  3. Token → AuthenticationManager
  4. Manager 遍歷 Providers,匹配支持 Token 類型的 Provider
  5. Provider → UserCacheService(檢查緩存)
  6. 緩存命中 → 返回用戶詳情;未命中 → 返回 null
  7. Provider 檢查緩存結果
  8. 未命中 → UserDetailsService 讀取後端存儲(屬性文件/數據庫/LDAP)
  9. UserDetailsService 返回用戶詳情或拋異常
  10. Provider 比對密碼 → 匹配則返回 Authentication,否則拋異常
  11. Manager 返回 Authentication → APF
  12. APF 將 Authentication 存入 SecurityContext(SIF 創建)
  13. APF 調用 chain.doFilter() 繼續鏈

簡單示例應用部署與驗證

項目結構

  • index.jsp:歡迎頁,含受保護資源鏈接、登錄鏈接
  • protected1.jsp、protected2.jsp:受保護資源(需 ROLE_HEAD_OF_ENGINEERING)
  • login.jsp:登錄表單(提交到 /j_acegi_security_check)
  • accessDenied.jsp:403 頁面

web.xml 最小配置

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

部署步驟

  1. 下載 Acegi 1.0.3,解壓 acegi-security-sample-tutorial.war 取出 WEB-INF/lib 所有 JAR
  2. 示例 acegisample.war 複製到 Tomcat webapps
  3. JAR 複製到示例 WEB-INF/lib
  4. 啟動 Tomcat,訪問 https://localhost:8080/acegisample/

驗證場景

  • 點擊受保護鏈接 → 自動跳轉登錄頁
  • 輸入 alice/123(角色 ROLE_HEAD_OF_ENGINEERING) → 登錄成功 → 重定向回目標頁
  • 直接訪問登錄頁 → 登錄後跳轉默認 protected1.jsp
  • 無角色用戶訪問受保護頁 → 顯示 Access Denied

總結與展望

本文建立了 Acegi 架構模型 → 組件依賴 → 過濾器鏈 → XML 配置 → 示例驗證 完整認知鏈。核心洞見:

  1. 過濾器鏈 將安全關注點模塊化、順序化、可組合
  2. Spring IOC 解耦組件創建與依賴,實現聲明式配置
  3. SecurityContextHolder 實現線程級安全上下文傳播
  4. Provider/Voter 模式 支援多種後端存儲與決策邏輯擴展

後續系列將深入:LDAP 目錄服務整合(第 2 部分)、方法級安全(第 3 部分)、JSF 整合(第 4-5 部分)。

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