From Gossip@caterpillar

Acegi Gossip: Acegi 元件





入門Acegi最重要的是了解基本架構,如此就不會被一堆設定檔案搞的混頭轉向,從先前「第一個Acegi程式」,可以看到Acegi系統包括的四個主要類型元件:Filter、Manager、Provider與Handler。
當一個請求到來時,在安全處理上最高層的元件,像是會話處理、驗證、登出等,並呼叫對應的物件進行處理。
真正處理驗證、登出等安全服務之元件,Manager管理Provider所提供的安全相關資訊。
提供安全相關資訊給Manager,安全資訊來源可能是記憶體中的物件、檔案、資料庫等儲存媒介,安全資訊包括了使用者名稱、密碼、角色等訊息。
有時會將一個安全服務分作數個小任務來進行,每個小任務由一個Handler來進行處理,如此在處理安全服務或設定Acegi時可以更有彈性,例如依需求處理登出時Session的失效與Cookie的失效。

Acegi使用Filter來對請求進行驗證與授權等安全服務:
    <!-- Filter Chain -->
     <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">  
       <property name="filterInvocationDefinitionSource">  
          <value>  
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
            PATTERN_TYPE_APACHE_ANT 
            /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,
                 exceptionTranslationFilter,filterSecurityInterceptor

         </value> 
      </property> 
    </bean>

以下介紹主要的幾個Filter:
通常是Filter Chain中第一個Filter,會建立Security Context 物件用以儲存安全相關資訊,後續的Filter若有需要儲存或取得安全相關資訊,即可利用Security Context 物件,如果Security Context物件中的資訊有所變動,Session Integration Filter會將變動儲存至Session物件之中,否則將Security Context物件棄置,例如「第一個Acegi程式」中所使用的Authentication Processing Filter,即利用Security Context物件來儲存使用者名稱、密碼等使用者資訊。

當使用者存取受保護資源而需要登入時,Authentication Processing Filter可提供表單來源給使用者,之後從使用者的請求(物件)中取得名稱、密碼並建立authentication token以儲存資訊,接著將之交給驗證管理員(authentication manager)進行以進行使用者的比對,所以基本上,Authentication Processing Filter需要設定以下的資訊:
<!-- 驗證處理,使用表單 -->
    <bean id="authenticationProcessingFilter"
          class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> 
        <!-- 驗證管理員,處理驗證資訊提供者  -->
        <property name="authenticationManager" ref="authenticationManager"/> 
        <!-- 驗證失敗URL -->
        <property name="authenticationFailureUrl" value="/acegilogin.jsp"/> 
        <!-- 驗證成功預設URL -->
        <property name="defaultTargetUrl" value="/protected/userinfo.jsp"/> 
        <!-- 驗證處理的提交位址 -->
        <property name="filterProcessesUrl" value="/j_acegi_security_check"/> 
    </bean>

當驗證管理員進行使用者的比對、取得細節資訊並返回Authentication Processing Filter後,Authentication Processing Filter會建立Authentication並將取得的使用者資訊儲存在Security Context物件中,然後交給下一個Filter繼續進行處理。

當驗證或授權過程中發生例外時,Exception Translation Filter處理例外。
    <!-- 發生驗證錯誤或權限錯誤時的處理 -->
    <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> 
        <property name="authenticationEntryPoint"> 
            <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> 
                <property name="loginFormUrl" value="/acegilogin.jsp"/> 
                <property name="forceHttps" value="false"/> 
            </bean> 
        </property> 
        <property name="accessDeniedHandler"> 
            <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> 
                <property name="errorPage" value="/accessDenied.jsp"/> 
            </bean> 
        </property> 
    </bean>      

管理登出的處理,實際的登出處理會交給Handler,您可以設置登出後的顯示頁面來源,在 第一個Acegi 程式 - 登出、自動Cookies登入 中,使用了SecurityContextLogoutHandler來讓Session交效。
     <!-- 登出處理 --> 
    <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter"> 
        <constructor-arg value="/acegilogin.jsp"/> <!-- 登出後的顯示頁面 --> 
            <constructor-arg> 
               <list> 
                   <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/> 
               </list> 
        </constructor-arg> 
    </bean>

用來決定是否授權,驗證與授權是一體的,所以在Authentication Processing Filter之後必須設定Interceptor filters,Interceptor filters使用您所設定的存取控制策略(access control policy)來決定是否授權,一個使用者的存取控制策略定義了使用者、密碼、角色等資訊:
caterpillar=123456,ROLE_SUPERVISOR

您使用Interceptor filters來進行存取控制策略的設定,設定驗證管理者與存取決策理員(Access Decision Manager),受保護的資源可存取之角色,存取決策管理員會以投票方式決定資源是否授權,例如:
    <!-- FilterSecurityInterceptor 對 URI 進行保護 -->
    <bean id="filterSecurityInterceptor"
          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_SUPERVISOR,ROLE_USER
            </value>
        </property>
    </bean>