程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Acegi源碼研究(五):七劍下天山

Acegi源碼研究(五):七劍下天山

編輯:關於JAVA

在Acegi初體驗及初解剖(http://rmn190.javaeye.com/blog/332711)裡, 通過對web.xml和applicationContext-acegi-security.xml的跟蹤,我們得出被Acegi攔截下的請求最終交到了filterInvocationDefinitionSource配置下的幾個Filter的實現類來處理. 它們是怎麼處理這個請求的呢? 在Acegi(三): Acegi? Who are you? ,我們聽說江湖中有"七劍", 但這麼久了"七劍"怎麼還 沒露面呢? 這篇博客中我們將看到下天山的"七劍".

首先我看下都有哪些Bean參於了Acegi的保衛工作, 如下圖所示:

上面是靜態的定義, 再看下圖的動態調用圖:

這裡結合著上圖,我們跟著浏覽器發出的請求走一遍.

Step1: 對上就上圖中數字1,這裡浏覽器發出一個請求.

Step2: Web服務器,我們這裡的Tomcat接受到Step1發來的HTTP請求, 把裡面的信息抽取出來,組裝成一個Request 對象, 同時Tomcat也生成了一個Response對象,這樣接下的Request穿過的Filter都有機會來修改這個Response對象了, 也正是Acegi抓住了這個機會利用Filter來改變Response裡的值達到保護我們系統的作用.這裡Request到達圖中的"Filter chain proxy", 我們還記得web.xml中配置的" FilterToBeanProxy "及基配置參數 FilterChainProxy(targetClass的值), 再看Bean圖中的 filterChainProxy,這裡我們動態地感覺到這個 filterChainProxy的存在了.通過配置中的" /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor" 一句我們告訴 filterChainProxy 當Request來時,都有哪些Filter處理這個Request.

Step3/Step4: filterChainProxy調用filterChain中的第一個Filter,也就是 httpSessionContextIntegrationFilter . 這個httpSessionContextIntegrationFilter 是 HttpSessionContextIntegrationFilter類的實例, 這個類正是"七劍"之一. 從它的名字上,我們也隱隱約約地感覺到了點什麼: 把Context integrate 到HttpSession中? 對的, 在HttpSessionContextIntegrationFilter的 doFilter方法裡Acegi從HttpSession中獲得 SecurityContext 對象(或沒有的話新建個), 隨後再把這個 SecurityContext存放到 SecurityContextHolder中, 很自然嘛, SecurityContextHolder 就是用來放 SecurityContext的. 做了這些處理後, httpSessionContextIntegrationFilter通過 chain.doFilter方法將執行權交給下一filter.

我們例子中下一個filter就是 authenticationProcessingFilter,它是 AuthenticationProcessingFilter的實例,看它名字裡有Authentication跟"七劍"中的 Authentication有關系? 不錯, authenticationProcessingFilter類中有一個 requiresAuthentication方法, 顧名思義,它是看當前的Request是否是用來做驗證的,也就是說是否是登錄的. 這就用到了Bean配置 authenticationProcessingFilter裡屬性, 看Acegi的源碼可以得到驗證. 接下來, 在方法 attemptAuthentication中Acegi從Request中取出 username和 password組建一個 Authentication 對象, 再由配置中的 authenticationManager來加以驗證,若"暗號"沒對上的話, 就有一個 AuthenticationException異常拋出, authenticationProcessingFilter catch住這個 AuthenticationException,再通過 sendRedirect方法在浏覽器中指向 authenticationFailureUrl的值" /login.jsp?login_error=1 ". 若"暗號"對上了,將通過方法 successfulAuthentication重定向到 defaultTargetUrl指定的頁面, 同時Acegi把對上"暗號"的 Authentication對象通過方法 SecurityContextHolder.getContext().setAuthentication存放到 SecurityContext中,以備後用.

Step5/Step6: Acegi將Request(當然還有Response)交給下一個Fillter, 我們例子中是 filterInvocationInterceptor(實際上交給了 exceptionTranslationFilter,這裡我們為了討論的方便,假定交給了 filterInvocationInterceptor ),這個filter再從SecurityContextHolder中取出SecurityContext,再取出裡面的已經對上"暗號"的Authentication對象(此對象在本例中實際上是封裝了users.properties裡這樣的" james=tom@1231,ROLE_TECHNICIAN "鍵值對), 再把這個 Authentication對象交給當前bean中配置的 accessDecisionManager屬性以決定 Authentication是否能訪問它想訪問的資源.經 accessDecisionManager"研究"後發現可以訪問,此時Acegi即將Request/Response交給我們系統裡配置的相應方法(如Struts裡配置的某一method).若"研究"時發現沒權限,則以異常的方式交給上面提到的 exceptionTranslationFilter,這個filter再重定向到 loginFormUrl指定的URL上.

到這步驟已走完了, 那怎麼沒看到"七劍"中的另三劍呢? 它們是 GrantedAuthority , UserDetails , Us erDetailsService . 實際上它們在filterInvocationInterceptor中用到了, 不過當時為了討論的方便,並沒有寫出來. 是這樣的, 在決定一個 Authentication是否可以訪問它想要的資源時, accessDecisionManager會從 Authentication裡 調用getAuthorities得到它的 GrantedAuthority[] , 再將它們與通過Us erDetailsService

得到的 UserDetails 對象裡方法返回的GrantedAuthority[]一一比較, 若在比較過程中發現有個對應上了, 就表示有權訪問,否則即無權. 這裡所論述的過程正是上面 accessDecisionManager所做的"研究".

好了,至此, 我們通過跟蹤請求的來龍去脈把 applicationContext-acegi-security.xml配置中的Filter走了一遍,更重要的是走filter時,我們與Acegi江湖裡的鼎鼎大名的"七劍"有了短暫但美好的接觸.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved