隨筆-62  評論-29  文章-0  trackbacks-0

          對于一個典型的Web應(yīng)用,完善的認(rèn)證和授權(quán)機制是必不可少的,在SpringFramework中,Juergen Hoeller提供的范例JPetStore給了一些這方面的介紹,但還遠(yuǎn)遠(yuǎn)不夠,Acegi是一個專門為SpringFramework提供安全機制的 項目,全稱為Acegi Security System for Spring,當(dāng)前版本為0.5.1,就其目前提供的功能,應(yīng)該可以滿足絕大多數(shù)應(yīng)用的需求。

          本文的主要目的是希望能夠說明如何在基于Spring構(gòu)架的Web應(yīng)用中使用Acegi,而不是詳細(xì)介紹其中的每個接口、每個類。注意,即使對已經(jīng)存在的Spring應(yīng)用,通過下面介紹的步驟,也可以馬上享受到Acegi提供的認(rèn)證和授權(quán)。

          基礎(chǔ)工作

          在你的Web應(yīng)用的lib中添加Acegi下載包中的acegi-security.jar

          web.xml

          實現(xiàn)認(rèn)證和授權(quán)的最常用的方法是通過filter,Acegi亦是如此,通常Acegi需要在web.xml添加以下5個filter:

                      

          <filter>

          <filter-name>Acegi Channel Processing Filter</filter-name>

          <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>

          <init-param>

          <param-name>targetClass</param-name>

          <param-value>net.sf.acegisecurity.securechannel.ChannelProcessingFilter</param-value>

          </init-param>

          </filter>

          <filter>

          <filter-name>Acegi Authentication Processing Filter</filter-name>

          <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>

          <init-param>

          <param-name>targetClass</param-name>

          <param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value>

          </init-param>

          </filter>

          <filter>

          <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>

          <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>

          <init-param>

          <param-name>targetClass</param-name>

          <param-value>net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value>

          </init-param>

          </filter>

          <filter>

          <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>

          <filter-class>net.sf.acegisecurity.ui.AutoIntegrationFilter</filter-class>

          </filter>

          <filter>

          <filter-name>Acegi HTTP Request Security Filter</filter-name>

          <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>

          <init-param>

          <param-name>targetClass</param-name>

          <param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>

          </init-param>

          </filter>

          最先引起迷惑的是net.sf.acegisecurity.util.FilterToBeanProxy,Acegi自己的文檔上解釋 是:“What  FilterToBeanProxy does is delegate the Filter's methods through to a bean which is obtained from the Spring application context. This enables the bean to benefit from the Spring application context lifecycle support and configuration flexibility.”,如希望深究的話,去看看源代碼應(yīng)該不難理解。

          再下來就是添加filter-mapping了:

                      

          <filter-mapping>

          <filter-name>Acegi Channel Processing Filter</filter-name>

          <url-pattern>/*</url-pattern>

          </filter-mapping>

          <filter-mapping>

          <filter-name>Acegi Authentication Processing Filter</filter-name>

          <url-pattern>/*</url-pattern>

          </filter-mapping>

          <filter-mapping>

          <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>

          <url-pattern>/*</url-pattern>

          </filter-mapping>

          <filter-mapping>

          <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>

          <url-pattern>/*</url-pattern>

          </filter-mapping>

          <filter-mapping>

          <filter-name>Acegi HTTP Request Security Filter</filter-name>

          <url-pattern>/*</url-pattern>

          </filter-mapping>

           

          這里,需要注意以下三點:

          1) 這幾個filter的順序是不能更改的,順序不對將無法正常工作;

          2) 如果你的應(yīng)用不需要安全傳輸,如https,則將"Acegi Channel Processing Filter"相關(guān)內(nèi)容注釋掉即可;

          3) 如果你的應(yīng)用不需要Spring提供的遠(yuǎn)程訪問機制,如Hessian and Burlap,將"Acegi HTTP BASIC Authorization Filter"相關(guān)內(nèi)容注釋掉即可。

           

          applicationContext.xml

          接下來就是要添加applicationContext.xml中的內(nèi)容了,從剛才FilterToBeanFactory的解釋可以看出,真正的filter都在Spring的applicationContext中管理:

          1)首先,你的數(shù)據(jù)庫中必須具有保存用戶名和密碼的table,Acegi要求table的schema必須如下:

                      

          CREATE TABLE users (

          username VARCHAR(50) NOT NULL PRIMARY KEY,

          password VARCHAR(50) NOT NULL,

          enabled BIT NOT NULL

          );

          CREATE TABLE authorities (

          username VARCHAR(50) NOT NULL,

          authority VARCHAR(50) NOT NULL

          );

          CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority );

          ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username)

          REFERENCES users

          (username);

          2)添加訪問你的數(shù)據(jù)庫的datasource和Acegi的jdbcDao,如下:

                      

          <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

          <property name="driverClassName"><value>${jdbc.driverClassName}</value></property>

          <property name="url"><value>${jdbc.url}</value></property>

          <property name="username"><value>${jdbc.username}</value></property>

          <property name="password"><value>${jdbc.password}</value></property>

          </bean>

          <bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">

          <property name="dataSource"><ref bean="dataSource"/></property>

          </bean>

          3)添加DaoAuthenticationProvider:

                      

          <bean id="daoAuthenticationProvider"

          class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">

          <property name="authenticationDao"><ref bean="authenticationDao"/></property>

          <property name="userCache"><ref bean="userCache"/></property>

          </bean>

          <bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">

          <property name="minutesToIdle"><value>5</value></property>

          </bean>

          如果你需要對密碼加密,則在daoAuthenticationProvider中加入:<property name="passwordEncoder"><ref bean="passwordEncoder"/></property>,Acegi提供了幾種加密方法,詳細(xì)情況可看包 net.sf.acegisecurity.providers.encoding

          4)添加authenticationManager:

                      

          <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">

          <property name="providers">

          <list>

          <ref bean="daoAuthenticationProvider"/>

          </list>

          </property>

          </bean>

          5)添加accessDecisionManager:

                      

          <bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">

          <property name="allowIfAllAbstainDecisions">

          <value>false</value>

          </property>

          <property name="decisionVoters">

          <list><ref bean="roleVoter"/></list>

          </property>

          </bean>

          <bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>

          6)添加authenticationProcessingFilterEntryPoint:

                      

          <bean id="authenticationProcessingFilterEntryPoint"

          class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">

          <property name="loginFormUrl"><value>/acegilogin.jsp</value></property>

          <property name="forceHttps"><value>false</value></property>

          </bean>

          其中acegilogin.jsp是登陸頁面,一個最簡單的登錄頁面如下:

                      

          <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>

          <%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>

          <%@ page import="net.sf.acegisecurity.AuthenticationException" %>

          <html>

          <head>

          <title>Login</title>

          </head>

          <body>

          <h1>Login</h1>

          <form action="<c:url value='j_acegi_security_check'/>" method="POST">

          <table>

          <tr><td>User:</td><td><input type='text' name='j_username'></td></tr>

          <tr><td>Password:</td><td><input type='password' name='j_password'></td></tr>

          <tr><td colspan='2'><input name="submit" type="submit"></td></tr>

          <tr><td colspan='2'><input name="reset" type="reset"></td></tr>

          </table>

          </form>

          </body>

          </html>

          7)添加filterInvocationInterceptor:

                      

          <bean id="filterInvocationInterceptor"

          class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">

          <property name="authenticationManager">

          <ref bean="authenticationManager"/>

          </property>

          <property name="accessDecisionManager">

          <ref bean="accessDecisionManager"/>

          </property>

          <property name="objectDefinitionSource">

          <value>

          CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

          \A/sec/administrator.*\Z=ROLE_SUPERVISOR

          \A/sec/user.*\Z=ROLE_TELLER

          </value>

          </property>

          </bean>

          這里請注意,要objectDefinitionSource中定義哪些頁面需要權(quán)限訪問,需要根據(jù)自己的應(yīng)用需求進(jìn)行修改,我上面給出的定義的意思是這樣的:

          a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比較請求路徑時全部轉(zhuǎn)換為小寫

          b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有權(quán)限為ROLE_SUPERVISOR才能訪問/sec/administrator*的頁面

          c. \A/sec/user.*\Z=ROLE_TELLER意思是只有權(quán)限為ROLE_TELLER的用戶才能訪問/sec/user*的頁面

          8)添加securityEnforcementFilter:

                      

          <bean id="securityEnforcementFilter"

          class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">

          <property name="filterSecurityInterceptor">

          <ref bean="filterInvocationInterceptor"/>

          </property>

          <property name="authenticationEntryPoint">

          <ref bean="authenticationProcessingFilterEntryPoint"/>

          </property>

          </bean>

          9)添加authenticationProcessingFilter:

                      

          <bean id="authenticationProcessingFilter"

          class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">

          <property name="authenticationManager">

          <ref bean="authenticationManager"/>

          </property>

          <property name="authenticationFailureUrl">

          <value>/loginerror.jsp</value>

          </property>

          <property name="defaultTargetUrl">

          <value>/</value>

          </property>

          <property name="filterProcessesUrl">

          <value>/j_acegi_security_check</value>

          </property>

          </bean>

          其中authenticationFailureUrl是認(rèn)證失敗的頁面。

          10)如果需要一些頁面通過安全通道的話,添加下面的配置:

                      

          <bean id="channelProcessingFilter"

          class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">

          <property name="channelDecisionManager">

          <ref bean="channelDecisionManager"/>

          </property>

          <property name="filterInvocationDefinitionSource">

          <value>

          CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

          \A/sec/administrator.*\Z=REQUIRES_SECURE_CHANNEL

          \A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL

          \A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL

          \A.*\Z=REQUIRES_INSECURE_CHANNEL

          </value>

          </property>

          </bean>

          <bean id="channelDecisionManager"

          class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl">

          <property name="channelProcessors">

          <list>

          <ref bean="secureChannelProcessor"/>

          <ref bean="insecureChannelProcessor"/>

          </list>

          </property>

          </bean>

          <bean id="secureChannelProcessor"

          class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/>

          <bean id="insecureChannelProcessor"

          class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/>

          缺少了什么?

          Acegi目前提供了兩種“secure object”,分別對頁面和方法進(jìn)行安全認(rèn)證管理,我這里介紹的只是利用FilterSecurityInterceptor對訪問頁面的權(quán)限控制,除 此之外,Acegi還提供了另外一個Interceptor——MethodSecurityInterceptor,它結(jié)合runAsManager可 實現(xiàn)對對象中的方法的權(quán)限控制,使用方法可參看Acegi自帶的文檔和contact范例。

          最后要說的

          本來以為只是說明如何使用Acegi而已,應(yīng)該非常簡單,但真正寫起來才發(fā)現(xiàn)想要條理清楚的理順?biāo)行枰腷ean還是很困難的,但愿我沒有遺漏太 多東西,如果我的文章有什么遺漏或錯誤的話,還請參看Acegi自帶的quick-start范例,但請注意,這個范例是不能直接拿來用的。



          posted on 2009-06-29 15:09 閱讀(2348) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 壤塘县| 南和县| 伊吾县| 阳朔县| 慈利县| 阿拉善左旗| 醴陵市| 陕西省| 酒泉市| 田林县| 尚义县| 岢岚县| 凌海市| 清水河县| 桐柏县| 惠安县| 伊川县| 建昌县| 阿克苏市| 延边| 阆中市| 安顺市| 九江县| 迭部县| 肇庆市| 大余县| 山丹县| 鹤壁市| 芦山县| 乌兰县| 新田县| 容城县| 安吉县| 蒙山县| 九龙城区| 昌乐县| 什邡市| 左贡县| 弥渡县| 津南区| 兴安盟|