Acegi在appfuse中的應用

          Posted on 2008-01-17 16:34 Boris 閱讀(243) 評論(0)  編輯  收藏
          Acegi是Spring Framework 下最成熟的安全系統,它提供了強大靈活的企業級安全服務,如完善的認證和授權機制,Http資源訪問控制,Method 調用訪問控制,Access Control List (ACL) 基于對象實例的訪問控制,Yale Central Authentication Service (CAS) 耶魯單點登陸,X509 認證,當前所有流行容器的認證適配器,Channel Security頻道安全管理等功能。
          我著重說明一下appfuse是怎么使用acegi的:
          1)web.xml:
          <filter>
          <filter-name>securityFilter</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>
          

          Acegi通過實現了Filter接口的FilterToBeanProxy提供一種特殊的使用Servlet Filter的方式,它委托Spring中的Bean -- FilterChainProxy來完成過濾功能,這好處是簡化了web.xml的配置,并且充分利用了Spring IOC的優勢。FilterChainProxy包含了處理認證過程的filter列表,每個filter都有各自的功能。
          <filter-mapping>限定了FilterToBeanProxy的URL匹配模式,有如下的請求才會受到權限控制。
          <filter-mapping>
          <filter-name>securityFilter</filter-name>
          <url-pattern>/j_security_check</url-pattern>
          </filter-mapping>
          <filter-mapping>
          <filter-name>securityFilter</filter-name>
          <url-pattern>/dwr/*</url-pattern>
          </filter-mapping>
          <filter-mapping>
          <filter-name>securityFilter</filter-name>
          <url-pattern>*.html</url-pattern>
          </filter-mapping>
          <filter-mapping>
          <filter-name>securityFilter</filter-name>
          <url-pattern>*.jsp</url-pattern>
          </filter-mapping>
          

          這里配置了其他的xml文件我們主要看/WEB-INF/security.xml。
          <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>/WEB-INF/applicationContext-*.xml,/WEB-INF/security.xml</param-value>
          </context-param>
          



          2)過濾的代理:
          在security中我們首先看到的是過濾代理:
          <!-- ======================== 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,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
          </value>
          </property>
          </bean>
          

          其中CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON是 將請求轉變成為小寫。
          PATTERN_TYPE_APACHE_ANT是按照ant的方式進行匹配模式
          FilterChainProxy會按順序來調用這些filter,使這些filter能享用Spring ioc的功能。


          3)基本驗證管理:
          我們先看一下它是怎么進行驗證管理的。
          <!-- 驗證管理 -->
          <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
          <property name="providers">
          <list>
          <!-- 從數據庫中讀取用戶信息驗證身份 -->
          <ref local="daoAuthenticationProvider"/>
          <!-- 匿名用戶身份認證 -->
          <ref local="anonymousAuthenticationProvider"/>
          <!-- 已存cookie中的用戶信息身份認證 -->
          <ref local="rememberMeAuthenticationProvider"/>
          </list>
          </property>
          </bean>
          <!-- 從數據庫中讀取用戶信息驗證身份 -->
          <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
          <property name="userDetailsService" ref="userDao"/>
          <property name="userCache" ref="userCache"/>
          <property name="passwordEncoder" ref="passwordEncoder"/>
          </bean>
          <!-- 匿名用戶身份認證 -->
          <bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
          <property name="key" value="anonymous"/>
          </bean>
          <!-- 已存cookie中的用戶信息身份認證 -->
          <bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
          <property name="key" value="appfuseRocks"/>
          </bean>
          

          首先daoAuthenticationProvider是從數據庫中讀取數據進行驗證。
          userDetailsService屬性使用了userDao進行的讀取(userDao實現org.acegisecurity.userdetails.UserDetailsService接口,而user類實現org.acegisecurity.userdetails.UserDetails才能userDetailsService里使用),還可以使用其他的方式比如直接鏈接數據源等等。
          userCache屬性注明使用緩存,對于不經常改變的user放到緩存里可以大大減少數據庫的負擔。也可以選擇不使用,如果不使用則每次都登錄都從數據中查詢用戶信息。
          passwordEncoder屬性則注明密碼加密的方法,
          使用加密器對用戶輸入的明文進行加密。Acegi提供了三種加密器:
          PlaintextPasswordEncoder—默認,不加密,返回明文.
          ShaPasswordEncoder—哈希算法(SHA)加密
          Md5PasswordEncoder—消息摘要(MD5)加密
          <bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.ShaPasswordEncoder"/>
          

          這里使用的哈希算法(SHA)加密。
          其次,anonymousAuthenticationProvider是給與匿名用戶一個匿名的權限anonymous。
          最后,rememberMeAuthenticationProvider則是把登錄的權限存儲在cookie里,不loginout時關閉瀏覽器,再度打開瀏覽器依舊保留權限(密碼修改時有特殊的限制)。
          驗證管理者(authenticationManager)包含三個驗證提供者(daoAuthenticationProvider, anonymousAuthenticationProvider,rememberMeAuthenticationProvider),當然可以適當的簡略。


          怎么進行驗證的呢?
          3)過濾:

          1.HttpSessionContextIntegrationFilter
          每次request前 HttpSessionContextIntegrationFilter從Session中獲取Authentication對象,在request完后, 又把Authentication對象保存到Session中供下次request使用,此filter必須其他Acegi filter前使用,使之能跨越多個請求。

          2. logoutFilter
          該Filter負責處理退出登錄后所需要的清理工作。它會把session銷毀,把ContextHolder清空, 把rememberMeServices從cookies中清除掉,然后重定向到指定的退出登陸頁面。

          3. authenticationProcessingFilter
          該Filter負責處理登陸身份驗證。當接受到與filterProcessesUrl所定義相同的請求時,它會首先通過AuthenticationManager來驗證用戶身份。如果驗證成功,則重定向到defaultTargetUrl所定義的成功登陸頁面。如果驗證失敗,則再從rememberMeServices中獲取用戶身份,若再獲取失敗,則重定向到authenticationFailureUrl所定義登陸失敗頁面。
          配置如下:
          <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
          <property name="authenticationManager" ref="authenticationManager"/>
          <property name="authenticationFailureUrl" value="/login.jsp?error=true"/>
          <property name="defaultTargetUrl" value="/"/>
          <property name="filterProcessesUrl" value="/j_security_check"/>
          <property name="rememberMeServices" ref="rememberMeServices"/>
          </bean>
          

          authenticationFailureUrl定義登陸失敗時轉向的頁面
          defaultTargetUrl定義登陸成功時轉向的頁面
          filterProcessesUrl定義登陸請求的頁面
          rememberMeServices用于在驗證成功后添加cookie信息

          4.securityContextHolderAwareRequestFilter
          該Filter負責通過Decorate Model(裝飾模式),裝飾的HttpServletRequest對象。其Wapper是ServletRequest包裝類HttpServletRequestWrapper的子類(SavedRequestAwareWrapper或SecurityContextHolderAwareRequestWrapper),附上獲取用戶權限信息,request參數,headers, Date headers 和 cookies 的方法。
          p.s. 如果把channelProcessingFilter放到securityContextHolderAwareRequestFilter前面則進行SSL的過濾。

          5.rememberMeProcessingFilter
          該Filter負責在用戶登錄后在本地機上記錄用戶cookies信息,免除下次再次登陸。檢查AuthenticationManager 中是否已存在Authentication對象,如果不存在則會調用RememberMeServices的aotoLogin方法來從cookies中獲取Authentication對象

          6.anonymousProcessingFilter
          該Filter負責為當不存在任何授權信息時,自動為Authentication對象添加userAttribute中定義的匿名用戶權限

          7.exceptionTranslationFilter
          該過濾器負責處理各種異常,然后重定向到相應的頁面中。

          8.filterInvocationInterceptor
          該過濾器會首先調用AuthenticationManager判斷用戶是否已登陸認證,如還沒認證成功,則重定向到登陸界面。認證成功,則并從Authentication中獲取用戶的權限。然后從objectDefinitionSource屬性獲取各種URL資源所對應的權限。最后調用AccessDecisionManager來判斷用戶所擁有的權限與當前受保華的URL資源所對應的權限是否相匹配。如果匹配失敗,則返回403錯誤(禁止訪問)給用戶。匹配成功則用戶可以訪問受保護的URL資源。
          <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
          <property name="authenticationManager" ref="authenticationManager"/>
          <property name="accessDecisionManager" ref="accessDecisionManager"/>
          <property name="objectDefinitionSource">
          <value>
          PATTERN_TYPE_APACHE_ANT
          /clickstreams.jsp*=admin
          /flushCache.*=admin
          /passwordHint.html*=ROLE_ANONYMOUS,admin,user
          /reload.*=admin
          /signup.html*=ROLE_ANONYMOUS,admin,user
          /users.html*=admin
          /**/*.html*=admin,user
          </value>
          </property>
          </bean>
          

          其中使用了accessDecisionManager,他是經過投票機制來決定是否可以訪問某一資源(URL或方法)。allowIfAllAbstainDecisions為false時如果有一個或以上的decisionVoters投票通過,則授權通過。可選的決策機制有ConsensusBased和UnanimousBased。
          <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
          <property name="allowIfAllAbstainDecisions" value="false"/>
          <property name="decisionVoters">
          <list>
          <bean class="org.acegisecurity.vote.RoleVoter">
          <property name="rolePrefix" value=""/>
          </bean>
          </list>
          </property>
          </bean>
          

          roleVoter表示必須是以rolePrefix設定的value開頭的權限才能進行投票,如AUTH_ , ROLE_等,實現用戶分組。
          4)方法執行前權限驗證
          <!-- 類代理 -->
          <aop:config>
          <aop:advisor id="managerSecurity" advice-ref="methodSecurityInterceptor" pointcut="execution(* cn.scs.service.UserManager.*(..))"/>
          <aop:advisor id="personManagerSecurity" advice-ref="methodSecurityInterceptor" pointcut="execution(* cn.scs.service.PersonManager.*(..))"/>
          </aop:config>
          <!-- 在執行方法前進行攔截,檢查用戶權限信息 -->
          <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
          <property name="authenticationManager" ref="authenticationManager"/>
          <property name="accessDecisionManager" ref="accessDecisionManager"/>
          <property name="objectDefinitionSource">
          <value>
          cn.scs.service.UserManager.getUsers=admin
          cn.scs.service.UserManager.removeUser=admin
          cn.scs.service.PersonManager.getPeople=ROLE_ANONYMOUS
          </value>
          </property>
          </bean>
          

          可以把類MethodSecurityInterceptor注入到代理了的類中,實現在方法執行之前進行驗證。
          aecgi的常用標簽(一共只有4個)
          <authz:authorize>
          

          這個標簽來控制頁面元素的顯示與否。
          主要有如下屬性
          ifAnyGranted 只要有任意權限相當于或者(||)這個經常使用
          ifAllGranted 需要有所列出的全部權限 相當于并且(&&)
          ifNotGranted 不能有任意權限 相當于非(!)和第一個配合使用
          用這些就可以控制頁面元素的顯示與否了
          例:
          <authz:authorize ifAnyGranted="ROLE_ADMIN">
          <display:column property="infoId" sortable="true" href="infoContentform.html?typeId=${typeId}" media="html"
          paramId="infoId" paramProperty="infoId" titleKey="infoContent.infoId"/>
          </authz:authorize>
          <authz:authorize ifNotGranted="ROLE_ADMIN">
          <display:column property="infoId" sortable="true" titleKey="infoContent.infoId"/>
          </authz:authorize>
          

          結合了<authz:authorize>控制displayTag標簽的顯示。

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          posts - 1, comments - 0, trackbacks - 0, articles - 2

          Copyright © Boris

          主站蜘蛛池模板: 南昌县| 玉环县| 沙河市| 黄龙县| 阿鲁科尔沁旗| 彩票| 黄平县| 黑龙江省| 商南县| 苍梧县| 海晏县| 平湖市| 美姑县| 吐鲁番市| 永泰县| 定安县| 土默特左旗| 理塘县| 巴南区| 五指山市| 全州县| 益阳市| 黄山市| 彩票| 凌云县| 建平县| 玛多县| 永春县| 嵩明县| 瑞昌市| 文山县| 博兴县| 邮箱| 大安市| 枣庄市| 赤壁市| 安宁市| 甘谷县| 邢台县| 读书| 赤峰市|