Java學(xué)習(xí)

          java,spring,structs,hibernate,jsf,ireport,jfreechart,jasperreport,tomcat,jboss -----本博客已經(jīng)搬家了,新的地址是 http://www.javaly.cn 如果有對(duì)文章有任何疑問(wèn)或者有任何不懂的地方,歡迎到www.javaly.cn (Java樂(lè)園)指出,我會(huì)盡力幫助解決。一起進(jìn)步

           

          淺談Acegi配置

          Acegi配置文檔
          作者:javafish(likunkun)
          Email:javafish@sunxin.org
          Acegi是基于Spring的一個(gè)開(kāi)源的安全認(rèn)證框架,現(xiàn)在的最新版本是1.04。Acegi的特點(diǎn)就是有很多的過(guò)濾器:不過(guò)我們也用不到這么 多的過(guò)濾器,只是可以把它們看作為一個(gè)個(gè)的模塊,在用的時(shí)候加上自己用的著的即可,由于認(rèn)證的流程的方面比較復(fù)雜導(dǎo)致它的配置很復(fù)雜,如果能摸清它的工作 原理還是不太難.下面用比較順著人思維的流程過(guò)一遍
          這里只列出常用的過(guò)濾器和攔載器
          1. 過(guò)濾器:HttpSessionContextIntegrationFilter,authenticationProcessingFilter,BasicProcessingFilter,RememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter
          2. 攔截器:filterSecurityInterceptor(其實(shí)它是過(guò)濾器,不過(guò)把它放在這里更能說(shuō)明它的功能),methodSecurityInterceptor
          看著上面的用紅色標(biāo)出的過(guò)濾器是用來(lái)認(rèn)證(表單和HTTP基本認(rèn)證,當(dāng)然還有別的不過(guò)這兩個(gè)比較長(zhǎng)用)它們是資源訪問(wèn)的入口.其它的過(guò)濾器是用來(lái) 輔助的:HttpSessionContextIntegrationFilter是用來(lái)把認(rèn)證信息記錄到Session中的 RememberMeProcessingFilter是以cookie的形式來(lái)保存認(rèn)證信息的. anonymousProcessingFilter是在匿名的時(shí)候(這時(shí)候是沒(méi)有認(rèn)證信息的)給這個(gè)用戶(hù)分配一個(gè)匿名的認(rèn)證信息, exceptionTranslationFilter總結(jié)一下異常并處理.在實(shí)際中選擇適合程序的即可.
          上面只是資源訪問(wèn)的入口,真正保護(hù)資源的是這兩個(gè)攔截器:filterSecurityInterceptor,攔截URL的類(lèi)(它是個(gè)過(guò)濾器)
          metohdSecurityInterceptor,攔截類(lèi)中方法的調(diào)用,它們?yōu)槭裁匆獢r截呢?就是想在訪問(wèn)或調(diào)用這些方法之前來(lái)判斷一下用戶(hù)是否有訪問(wèn)或調(diào)用的權(quán)限,有就通過(guò),沒(méi)有就踢出.
          除此之外,Acegi專(zhuān)門(mén)做了兩個(gè)管理器(實(shí)際上就是兩個(gè)類(lèi),為什么會(huì)用做這兩個(gè)管理器,因?yàn)檎J(rèn)證和授權(quán)都有一些的操作,這就需要專(zhuān)門(mén)做兩個(gè)管理 器了):authenticationManager(class= org.acegisecurity.providers.ProviderManager),授權(quán)管理器accessDecisionManager (class=org.acegisecurity.vote.AffirmativeBased)
          說(shuō)白了一個(gè)用于認(rèn)證用戶(hù),一個(gè)是用于權(quán)限的授于的
          先來(lái)說(shuō)認(rèn)證用戶(hù),認(rèn)證管理器有什么東西呢?只內(nèi)置了一些提供者:這些提供者呢又是什么呢,他們是提供用戶(hù)的驗(yàn)證身份信息的,比如從數(shù)據(jù)庫(kù)或配置文件里讀出 用戶(hù)名和密碼,在用戶(hù)的cookie里讀出身份信息(rememberMeProcessingFilter用到的[前面講了的,有印象吧]),或在 Session里讀出身份驗(yàn)證信息(HttpSessionContextIntegrationFilter起作用的),這里我們只說(shuō)一下從數(shù)據(jù)庫(kù)或配 置文件里讀出用戶(hù)名密碼來(lái)裝配驗(yàn)證信息的,其它的配置類(lèi)似可以找一下對(duì)應(yīng)api在Spring里配置即可, daoAuthenticationProvider是數(shù)據(jù)庫(kù)的提供者class= org.acegisecurity.providers.dao.DaoAuthenticationProvider,而它提供的服務(wù)呢又有幾種,數(shù) 據(jù)庫(kù)和配置文件(這是Acegi的兩個(gè)默認(rèn)的實(shí)現(xiàn))當(dāng)然也可以自己實(shí)現(xiàn)(實(shí)現(xiàn)userDetailsService接口就行)
          Java代碼 復(fù)制代碼
          1. <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">  
          2.         <property name="providers">  
          3.             <list>  
          4.                 <ref local="daoAuthenticationProvider"/>  
          5.             </list>  
          6.         </property>  
          7.     </bean>  
          8. <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
          9.         <!-- <property name="userDetailsService"><ref local="InMemoryDaoImpl"/></property> --><!-- 這里有兩種選擇 -->  
          10.         <property name="userDetailsService"><ref local="jdbcDaoImpl"/></property>  
          11.     </bean>  

          如果用戶(hù)名和密碼在配置文件里可以用InMemoryDaoImpl,class= org.acegisecurity.userdetails.memory.InMemoryDaoImpl,在這個(gè)類(lèi)的userMap里配置即可: javafish=java,ROLE_USER,配置了一個(gè)用戶(hù)名為javafish,密碼為java,用戶(hù)組為ROLE_USER的用戶(hù),不過(guò)最常用 的還是數(shù)據(jù)庫(kù)的JDBC實(shí)現(xiàn)(兩個(gè)二選一)org.acegisecurity.userdetails.jdbc.JdbcDaoImpl里面需要 usersByUsernameQuery和authoritiesByUsernameQuery還有數(shù)據(jù)源dataSource(有人問(wèn)為什么呢, userByUsernameQuery是用來(lái)通過(guò)用戶(hù)名來(lái)查密碼的,authoritiesByUsernameQuery是用來(lái)通過(guò)用戶(hù)名來(lái)查權(quán)限 的,查詢(xún)數(shù)據(jù)庫(kù)肯定的用數(shù)據(jù)源吧這個(gè)里是用的SpringFrameWork的DataSource)它們查詢(xún)的sql語(yǔ)句是有講究的,就是查密碼的時(shí)候 查三個(gè)第一個(gè)是username,第二個(gè)是password,第三個(gè)是是否可用,查權(quán)限的時(shí)候查兩個(gè):username和authorities(具體看 例子)
          Java代碼 復(fù)制代碼
          1. <bean id="InMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">  
          2.         <property name="userMap">  
          3.             <value>  
          4.                 javafish=java,ROLE_USER  
          5.             </value>  
          6.         </property>  
          7.     </bean>  
          8.     <bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">  
          9.         <property name="usersByUsernameQuery">  
          10.             <value>select username,password,enabled from users where username=?</value>  
          11.         </property>  
          12.         <property name="authoritiesByUsernameQuery">  
          13.             <value>select username,authority from authorities where username=?</value>  
          14.         </property>  
          15.         <property name="dataSource">  
          16.             <ref local="dataSource"/>  
          17.         </property>  
          18.     </bean>  
          19.       
          20.     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
          21.         <property name="driverClassName">  
          22.             <value>com.mysql.jdbc.Driver</value>  
          23.         </property>  
          24.         <property name="url">  
          25.             <value>jdbc:mysql://localhost:3306/test</value>  
          26.         </property>  
          27.         <property name="username">  
          28.             <value>root</value>  
          29.         </property>  
          30.         <property name="password">  
          31.             <value>javafish</value>  
          32.         </property>  
          33.     </bean>  

          下面說(shuō)一下授權(quán),授權(quán)管理器又有什么東西呢?accessDecisionManager,Acegi把授權(quán)方面弄的比較的形象化,把某個(gè)URL或方法是否可以被訪問(wèn)按投票的形式來(lái)決定,

          Acegi提出來(lái)了幾種方案:
          1. 如果有一個(gè)贊成就同意(具體的說(shuō)就是只要你在那個(gè)URL對(duì)應(yīng)的幾個(gè)用戶(hù)組中的一個(gè)就讓你訪問(wèn))
          2. 如果都贊成就同意(具本的說(shuō)就是那個(gè)URL對(duì)應(yīng)的幾個(gè)用戶(hù)組里都有你,你才能訪問(wèn))
          3. 如果都不反對(duì)就同意(這個(gè)在下面講投票者的時(shí)候再說(shuō))
          Java代碼 復(fù)制代碼
          1. <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">  
          2.         <property name="allowIfAllAbstainDecisions"><!-- 是否讓全部棄權(quán)的通過(guò) -->  
          3.             <value>false</value>  
          4.         </property>  
          5.         <property name="decisionVoters"><!-- 投票者們 -->  
          6.             <ref bean="roleVoter"/>  
          7.         </property>  
          8.     </bean>  

          而投票者呢:Acegi自己實(shí)現(xiàn)了一個(gè)投票者的類(lèi)RoleVoter:
          現(xiàn)在我用第一種方案,RoleVoter只是在URL對(duì)應(yīng)的用戶(hù)組里有ROLE_為前綴的才進(jìn)行投票,否則的話棄權(quán).(我們也可以在配置 RoleVoter的時(shí)候把ROLE_配置成為別的前綴如JAVA_),分別對(duì)URL對(duì)應(yīng)的每個(gè)用戶(hù)組投票,如果用戶(hù)在這個(gè)用戶(hù)組里就投贊成,不在投反對(duì) (在用戶(hù)組的前綴是ROLE_的前提下)這樣就不難體會(huì)第三種方案的用途了吧
          Java代碼 復(fù)制代碼
          1. <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">  
          2.         <property name="rolePrefix">  
          3.             <value>ROLE_</value><!-- 可以改成別的 -->  
          4.         </property>  
          5.     </bean>  

          這樣認(rèn)證管理器和授權(quán)管理器就ok了,別的無(wú)論是過(guò)濾器還是攔截器都會(huì)用到它們兩個(gè),因?yàn)樗鼈兌家?yàn)證而這兩個(gè)就是憑證.
          那么那兩個(gè)訪問(wèn)過(guò)濾器呢,先說(shuō)authenticationProcessingFilter是用于表單登陸的
          Java代碼 復(fù)制代碼
          1. <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">  
          2.         <property name="authenticationManager"><ref bean="authenticationManager"/></property>  
          3.         <property name="authenticationFailureUrl"><value>/failure.html</value></property><!--登陸失敗轉(zhuǎn)向的頁(yè)面  -->  
          4.         <property name="defaultTargetUrl"><value>/ok.html</value></property><!-- 登陸成功轉(zhuǎn)向的頁(yè)面 -->  
          5.         <property name="filterProcessesUrl"><value>/check</value></property><!-- 要驗(yàn)證的地址 -->  
          6.     </bean>  

          這樣的話加上上面配置的認(rèn)證管理器就已經(jīng)可以處理登陸了(注意的是它沒(méi)有用到授權(quán)管理器,因?yàn)樗皇莻€(gè)訪問(wèn)入口還沒(méi)有權(quán)限的授予)
          再說(shuō)一下HTTP基本認(rèn)證:它比上面的略復(fù)雜一點(diǎn)
          需要配置一個(gè)
          Java代碼 復(fù)制代碼
          1. <bean id="BasicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">  
          2.         <property name="realmName"><value>javafish</value></property><!-- 基本認(rèn)證對(duì)話框上顯示的字 -->  
          3.     </bean>  
          4. 然后  
          5. <bean id="BasicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">  
          6.         <property name="authenticationManager">  
          7.             <ref bean="authenticationManager"/>  
          8.         </property>  
          9.         <property name="authenticationEntryPoint">  
          10.             <ref bean="BasicProcessingFilterEntryPoint"/>  
          11.         </property>  
          12.     </bean>  

          即可.
          不過(guò)在HTTP基本認(rèn)證里需要注意的地方是:好多人配置好了怎么看不到效果啊,一開(kāi)始我也是很郁悶,看了BasicProcessingFilter的源代碼:
          String header = httpRequest.getHeader("Authorization");//我們一般進(jìn)入網(wǎng)頁(yè)測(cè)試的時(shí)候這里的header始終是null的
          Java代碼 復(fù)制代碼
          1. if (logger.isDebugEnabled()) {  
          2.             logger.debug("Authorization header: " + header);  
          3.         }  
          4.         if ((header != null) && header.startsWith("Basic ")) {//從這里可以看到一般的登陸基本認(rèn)證是不起作用的  
          5. .................  

          只有在服務(wù)器上配置哪個(gè)目錄在訪問(wèn)的時(shí)候用HTTP基本認(rèn)證,它才會(huì)起作用(一開(kāi)始還以為是Acegi的BUG呢)
          下面說(shuō)一下真正對(duì)URL資源的保護(hù)了filterSecurityInterceptor它的本質(zhì)是個(gè)過(guò)濾器,有了前面*管理器的基礎(chǔ)了這就很容易了:
          Java代碼 復(fù)制代碼
          1. <bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">  
          2.         <property name="authenticationManager">  
          3.             <ref local="authenticationManager"/>  
          4.         </property>  
          5.         <property name="accessDecisionManager">  
          6.             <ref local="accessDecisionManager"/>  
          7.         </property>  
          8.         <property name="objectDefinitionSource"><!-- 把URL和可訪問(wèn)的用戶(hù)組對(duì)應(yīng)起來(lái) -->  
          9.             <value>  
          10.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<!-- 把URL全部轉(zhuǎn)化為小寫(xiě) -->  
          11.                 PATTERN_TYPE_APACHE_ANT<!-- 以ANT的形式來(lái)配置路徑 -->  
          12.                 /ok.html=ROLE_USER  
          13.             </value>  
          14.         </property>  
          15.     </bean>  

          光這樣配置還是不夠的,因?yàn)楫?dāng)授權(quán)失敗的時(shí)候會(huì)拋出異常的,我們應(yīng)該配置一個(gè)異常過(guò)濾器來(lái)捕獲它,exceptionTranslationFilter它是用來(lái)捕獲異常的,看一下配置吧:
          Java代碼 復(fù)制代碼
          1. <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">  
          2.       <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>  
          3.       <property name="accessDeniedHandler">  
          4.         <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">  
          5.             <property name="errorPage" value="/failure.html"/><!-- 發(fā)生異常轉(zhuǎn)向的網(wǎng)頁(yè) -->  
          6.         </bean>  
          7.       </property>  
          8.    </bean>  
          9.    <bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">  
          10.         <property name="loginFormUrl"><value>/Login.html</value></property><!-- 得到表單的信息 -->  
          11.         <property name="forceHttps"><value>false</value></property><!-- 不用https -->  
          12.    </bean>  

          這樣就OK了
          最后說(shuō)一下對(duì)類(lèi)中方法的保護(hù):
          首先寫(xiě)一個(gè)類(lèi)并在spring中配置好:
          Java代碼 復(fù)制代碼
          1. package org.li.acegi;  
          2.   
          3. public class TestAcegi  
          4. {  
          5.     public void Role()  
          6.     {  
          7.         System.out.println("javafish");  
          8.     }  
          9. }  
          10. <bean id="testAcegi" class="org.li.acegi.TestAcegi"/>  

          然看寫(xiě)個(gè)servlet訪問(wèn)一下它
          Java代碼 復(fù)制代碼
          1. package org.li.servlet;  
          2.   
          3. import java.io.IOException;  
          4. import java.io.PrintWriter;  
          5.   
          6. import javax.servlet.ServletException;  
          7. import javax.servlet.http.HttpServlet;  
          8. import javax.servlet.http.HttpServletRequest;  
          9. import javax.servlet.http.HttpServletResponse;  
          10.   
          11. import org.li.acegi.TestAcegi;  
          12. import org.springframework.context.ApplicationContext;  
          13. import org.springframework.web.context.support.WebApplicationContextUtils;  
          14.   
          15. public class TestServlet extends HttpServlet  
          16. {  
          17.     private static final long serialVersionUID = -5610016980827214773L;  
          18.   
          19.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
          20.             throws ServletException, IOException  
          21.     {  
          22.         response.setContentType("text/html;charset=GBK");  
          23.         PrintWriter out = response.getWriter();  
          24.         ApplicationContext ctx =   
          25.             WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());  
          26.         TestAcegi test = (TestAcegi)ctx.getBean("testAcegi");  
          27.         test.Role();//訪問(wèn)TestAcegi類(lèi)的Role方法  
          28.         out.println("調(diào)用成功");  
          29.     }  
          30.   
          31.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
          32.             throws ServletException, IOException  
          33.     {  
          34.         doGet(request,response);  
          35.     }  
          36.   
          37. }  

          準(zhǔn)備工作做好了,開(kāi)始配置Acegi
          先在Spring里給Acegi做個(gè)代理:
          Java代碼 復(fù)制代碼
          1. <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
          2.         <property name="beanNames">  
          3.             <list>  
          4.                 <value>testAcegi</value><!-- 要代理的Bean的id -->  
          5.             </list>  
          6.         </property>  
          7.         <property name="interceptorNames">  
          8.             <list>  
          9.                 <value>methodSecurityInterceptor</value><!-- 代理為... -->  
          10.             </list>  
          11.         </property>  
          12.     </bean>  

          里面的methodSecurityInterceptor呢配置為:
          Java代碼 復(fù)制代碼
          1. <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">  
          2.         <property name="authenticationManager">  
          3.             <ref bean="authenticationManager"/>  
          4.         </property>  
          5.         <property name="accessDecisionManager">  
          6.             <ref bean="accessDecisionManager"/>  
          7.         </property>  
          8.         <property name="objectDefinitionSource"><!-- 對(duì)代理的類(lèi)的方法開(kāi)始配置權(quán)限 -->  
          9.             <value>org.li.acegi.TestAcegi.Role=ROLE_USER</value>  
          10.         </property>  
          11.     </bean>  

          這樣當(dāng)直接訪問(wèn)http://localhost:8080/AcegiWeb/servlet/TestServlet的時(shí)候會(huì)發(fā)現(xiàn)不可訪問(wèn),控件臺(tái)也不輸出”javafish”,當(dāng)輸入正確的用戶(hù)名和密碼之后便可以訪問(wèn).
          這樣它就對(duì)類(lèi)的方法調(diào)用起了保護(hù)的作用,這一點(diǎn)可以把Acegi應(yīng)用到DWR上效果是很理想的.
          對(duì)于Acegi有很多的過(guò)濾器不用全寫(xiě)在web.xml里,acegi提供了一個(gè)特殊的過(guò)濾器我們可以寫(xiě)成這樣,在Web.xml里:
          Java代碼 復(fù)制代碼
          1. <filter>  
          2.         <filter-name>Acegi</filter-name>  
          3.         <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>  
          4.         <init-param>  
          5.             <param-name>targetClass</param-name>  
          6.             <param-value>org.acegisecurity.util.FilterChainProxy</param-value>  
          7.         </init-param>  
          8.     </filter>  
          9.     <filter-mapping>  
          10.         <filter-name>Acegi</filter-name>  
          11.         <url-pattern>/*</url-pattern>  
          12.     </filter-mapping>  
          13.     <context-param>  
          14.         <param-name>contextConfigLocation</param-name>  
          15.         <param-value>  
          16.             /WEB-INF/applicationContext.xml  
          17.         </param-value>  
          18.     </context-param>  
          19.     <listener>  
          20.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
          21.     </listener>  
          22.       
          23.     <listener>  
          24.         <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>  
          25.     </listener>  
          26.     <listener>  
          27.         <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>  
          28.     </listener>  
          29.   <servlet>  
          30.     <servlet-name>TestServlet</servlet-name>  
          31.     <servlet-class>org.li.servlet.TestServlet</servlet-class>  
          32.   </servlet>  
          33.   
          34.   <servlet-mapping>  
          35.     <servlet-name>TestServlet</servlet-name>  
          36.     <url-pattern>/servlet/TestServlet</url-pattern>  
          37.   </servlet-mapping>  

          在Spring的配置文件里:
          Java代碼 復(fù)制代碼
          1. <bean id="chainProxy" class="org.acegisecurity.util.FilterChainProxy">  
          2.         <property name="filterInvocationDefinitionSource">  
          3.             <value>  
          4.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON  
          5.             PATTERN_TYPE_APACHE_ANT  
          6.             /**=HttpSessionContextIntegrationFilter,authenticationProcessingFilter,BasicProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor  
          7.             </value>  
          8.         </property>  
          9.     </bean>  

          posted on 2008-08-01 11:21 找個(gè)美女做老婆 閱讀(225) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          公告

          本blog已經(jīng)搬到新家了, 新家:www.javaly.cn
           http://www.javaly.cn

          常用鏈接

          留言簿(6)

          隨筆檔案

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 华池县| 庄河市| 遵化市| 常州市| 安平县| 黑山县| 巴南区| 隆安县| 通州区| 麻城市| 富民县| 博客| 张家港市| 武胜县| 彰化县| 阳朔县| 清丰县| 江陵县| 嘉祥县| 松滋市| 五大连池市| 稻城县| 高青县| 滨海县| 保德县| 渭南市| 新邵县| 溧水县| 尼勒克县| 河池市| 汉寿县| 隆化县| 麟游县| 淳安县| 凯里市| 古交市| 浙江省| 电白县| 渭南市| 德令哈市| 石河子市|