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

Acegi Security 實戰:在業務邏輯層透明獲取 Web 層用戶身份

     編輯:J2EE

問題背景

在 Struts+Spring+Hibernate 架構中,Web 層(Action/Controller)輕易通過 Session 獲取登錄用戶 ID,但業務邏輯層(Service/DAO)如何在不污染方法簽名(傳遞 userId 參數)的前提下獲得當前用戶身份,以實現方法級權限控制與審計日誌?Acegi Security(現 Spring Security 前身)提供了基於 ThreadLocal 的 SecurityContextHolder 機制,完美解決此問題。

環境搭建(Acegi 1.0)

1. 依賴包

下載 acegi-security-1.0.0.zip,將 JAR 放入 WEB-INF/lib。

2. 數據庫表結構

參考「一餐三碗」示例 Acegi.zip 中的 SQL 建表(userinfo、authorities、user_auth 等)。

3. web.xml 核心配置

<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>
<listener>
  <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
</listener>

4. applicationContext-acegi-security.xml 關鍵點

  • 過濾器鏈: httpSessionContextIntegrationFilter(核心,將 SecurityContext 綁定到 ThreadLocal)、authenticationProcessingFilter(表單登錄)、exceptionTranslationFilter、filterInvocationInterceptor(URL 權限)。
  • 認證提供者: DaoAuthenticationProvider + JdbcDaoImpl 讀取數據庫,支援 MD5 密碼編碼(Md5PasswordEncoder)。
  • 方法級攔截: MethodSecurityInterceptor + DataSourceMethodDefinitionSourceEditor 從數據庫動態加載方法-權限映射。

5. 業務接口與 AOP 配置

<!-- aoptest.xml -->
<bean id="interceptTarget" class="com.mysoft.pmi.testcase.aop.TestAOPInterfaceImpl" singleton="false"/>
<bean id="welcomeAdvice" class="com.mysoft.pmi.testcase.aop.WelcomeAdvice"/>
<bean id="aopProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces"><value>com.mysoft.pmi.testcase.aop.TestAOPInterface</value></property>
  <property name="interceptorNames"><list><value>welcomeAdvice</value></list></property>
  <property name="target"><ref bean="interceptTarget"/></property>
</bean>

核心代碼:Advice 中獲取用戶身份

public class WelcomeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        SecurityContext ctx = SecurityContextHolder.getContext();
        if (ctx != null) {
            Authentication auth = ctx.getAuthentication();
            if (auth != null) {
                Object principal = auth.getPrincipal();
                if (principal instanceof UserDetails) {
                    String username = ((UserDetails) principal).getUsername();
                    String password = ((UserDetails) principal).getPassword();
                    System.out.println("當前用戶: " + username);
                    // 此處可進行細粒度權限檢查、記錄審計日誌等
                } else {
                    System.out.println("匿名/非標準主體: " + principal);
                }
            }
        }
        // 繼續輸出調試信息...
    }
}

關鍵機制解析

  1. ThreadLocal 隔離: HttpSessionContextIntegrationFilter 在請求開始時從 Session 讀取 SecurityContext 綁定到 SecurityContextHolder(ThreadLocal),請求結束時清理。業務層線程相同,故可直接獲取。
  2. 非侵入式: 業務接口/實現類零依賴 Acegi API,僅在 Advice(切面)中引用,符合關注點分離。
  3. 擴展性: 結合 MethodSecurityInterceptor 實現聲明式方法權限;Advice 中可接入規則引擎實現數據級授權(如:同樣是「入庫單錄入」,原料庫管員只能錄原料,成品庫管員只能錄成品)。

測試驗證流程

  1. 訪問 acegilogin.jsp,輸入 root/root(數據庫預設)。
  2. 登錄成功進入 secure/index.jsp,點擊 Home 鏈接調用 testacegi.jsp。
  3. testacegi.jsp 通過 Spring 容器獲取代理 Bean,調用 test()/testAAA()。
  4. 控制台輸出 WelcomeAdvice 中打印的用戶名,驗證成功。

最佳實踐建議

  • 將 SecurityContextHolder 獲取邏輯封裝為獨立工具類(如 SecurityContextUtils.getCurrentUser()),業務代碼調用工具類而非直接依賴 Acegi API,便於未來遷移至 Spring Security。
  • 密碼加密:生產環境務必啟用 Md5PasswordEncoder 或更強算法(BCrypt),配置於 DaoAuthenticationProvider。
  • 方法級權限表 authorities 中 PROTECTED_RES 填寫完整接口方法名(如 com.mysoft.pmi.testcase.aop.TestAOPInterface.test),否則啟動時報錯。

結語

Acegi 通過 ThreadLocal 機制實現了 Web 身份向業務層的無縫傳遞,配合 Spring AOP 實現方法級安全與審計,是分層架構中解決「身份傳遞」的經典方案。代碼結構清晰、擴展性強,值得在項目中推廣應用。

作者:王保政
MSN: baozhengw999@hotmail.com
Email: baozhengw@netease.com
QQ: 29803446

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