以最新版的spring-security-3.0.2作為介紹對(duì)象,如果你了解Spring 2.0 Security的話,那就比較抱歉了,因?yàn)閟pring-security-3.0.2與2.0相比改動(dòng)很大,在2.0中的一些配置拿到3.0幾乎是行 不通的,如果你還沒有接觸過(guò)spring,那么以下是其地址:
Spring官方網(wǎng)址:http://www.springsource.org/
spring-security下載地址:
http://static.springsource.org/spring-security/site/downloads.html
我以其自帶的一個(gè)簡(jiǎn)單例子來(lái)介紹一下吧,因?yàn)檫@個(gè)例子配置不對(duì)的話極易報(bào)錯(cuò)(這個(gè)例子是個(gè)打包的War文件,但與文檔中的又不一樣,所以極易出錯(cuò)),我會(huì)對(duì)出現(xiàn)的錯(cuò)誤給予出錯(cuò)原因及解決方法。
首先通過(guò)spring-security地址下載到最新版的spring-security-3.0.2.RELEASE.zip,然后解壓開來(lái),在解壓開的目錄dist中,你會(huì)看到如下一些文件:
看到spring-security-samples-tutorial-3.0.2.RELEASE.war了嗎?我就以這個(gè)為例,把這個(gè)包拷貝 到你Web服務(wù)器(如Tomcat)的webapps目錄下,啟動(dòng)服務(wù)器后,會(huì)生成一個(gè)spring-security-samples- tutorial-3.0.2.RELEASE項(xiàng)目,可以把名字改短一點(diǎn)方便訪問(wèn),比如我這里改名為:spring-security,這樣通過(guò)http://127.0.0.1/spring-security可以直接訪問(wèn)了。
進(jìn)入目錄WEB-INF,可以看到如上的一些文件,其中,applicationContext-security.xml是權(quán)限控制配置文件,所 有的權(quán)限控制都是在其中配置的,bank-servlet.xml是系統(tǒng)的上下文配置文件,可以在其中配置訪問(wèn)路徑映射(類似于Struts-1.x中的 struts-config.xml或struts-2.x中的struts.xml文件),也可以在其中進(jìn)行一些裝配等工作,屬于spring級(jí)的,與 安全配置沒多大關(guān)系。
具體的文件內(nèi)容我就不展示了,因?yàn)榭梢宰约捍蜷_看,我這里只說(shuō)要注意的一些地方:
1、在web.xml中的配置
服務(wù)啟動(dòng)時(shí)加載applicationContext-security.xml文件:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext-security.xml </param-value> </context-param>
要過(guò)濾鏈接的形式
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
你一定注意到了,這里的filter-class與Spring2.0的不同之處,如果你了解Spring2.0的話,的確,在Spring2.0中為:
<filter-name>acegiFilterChain</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
這就是3.0與2.0改變很大的一個(gè)地方,2.0用的為Acegi,后來(lái)Acegi嵌入到了Spring中,成為了Spring Security,所以包的路徑也都改變了!
2、在applicationContext-security.xml中的配置
<http use-expressions="true"> <intercept-url pattern="/secure/extreme/**" access="hasRole('ROLE_SUPERVISOR')"/> <intercept-url pattern="/secure/**" access="isAuthenticated()" /> <!-- Disable web URI authorization, as we're using <global-method-security> and have @Secured the services layer instead <intercept-url pattern="/listAccounts.html" access="isRememberMe()" /> <intercept-url pattern="/post.html" access="hasRole('ROLE_TELLER')" /> --> <intercept-url pattern="/**" access="permitAll" /> <form-login /> <logout /> <remember-me /> <!-- Uncomment to enable X509 client authentication support <x509 /> --> <!-- Uncomment to limit the number of sessions a user can have --> <session-management invalid-session-url="/timeout.jsp"> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> </session-management> </http>
上面這段是初用者比較容易出錯(cuò)的地方,這其實(shí)也是寫這篇文章的主要原因之一,注意到第一行的黑體字:
<http use-expressions=”true”>
表示這里的配置可以使用一種表達(dá)式,這種表達(dá)式就是類似于isAuthenticated()這樣的寫法,在后面會(huì)看到與這種寫法不一樣但同樣可以達(dá)到相同效果的寫法。
intercept-url表示要攔截的url形式,比如
<intercept-url pattern=”/secure/**” access=”isAuthenticated()” />
表示根目錄下的secure目錄需要經(jīng)過(guò)驗(yàn)證后才能訪問(wèn)的。
<form-login />是Spring Security自動(dòng)為你生成的一個(gè)簡(jiǎn)陋的登錄頁(yè)面,即使你沒有創(chuàng)建任何登錄頁(yè)面,當(dāng)然你也可以修改,但不建議你修改,因?yàn)槟憧梢圆皇褂媚J(rèn)的,可以采用 如下方式:<form-login login-page=’/ login.html’/>自定義一個(gè)登錄頁(yè)面。
其他的說(shuō)明可以參考一個(gè)翻譯的中文文檔:
http://www.family168.com/tutorial/springsecurity3/html/ns-config.html
3、容易出錯(cuò)的地方
在上面的翻譯文檔(也是翻譯自官方文檔)或英文官方文檔中,給出的與上面例子功能相似的說(shuō)明大概是這樣的:
? <http auto-config='true'>
??? <intercept-url pattern="/**" access="ROLE_USER" />
? </http>
注意到與上面例子不同的地方了嗎?
還是注意第一行,這回不是<http use-expressions=”true”>而是<http auto-config=’true’>了,而下面的配置
<intercept-url pattern=”/**” access=”ROLE_USER” />也與上面的寫法不同,事實(shí)上如果是<http use-expressions=”true”>的話,這句access=”ROLE_USER”就是錯(cuò)的,正確的寫法就應(yīng)該為:hasRole(‘ROLE_USER’)。
這不得不說(shuō)這是Spring Security的文檔與例子不搭配的一個(gè)低級(jí)錯(cuò)誤,因?yàn)楫?dāng)一個(gè)使用者在打開例子又看到文檔說(shuō)明時(shí),他往往不知道這兩者有何區(qū)別,就如同我剛使用的時(shí)候一樣,我在使用<http use-expressions=”true”>的同時(shí),將access=”ROLE_USER”這種寫法也寫了進(jìn)來(lái),結(jié)果可想而知,報(bào)了錯(cuò)!報(bào)錯(cuò)信息諸如:
org.apache.jasper.JasperException: java.lang.IllegalArgumentException: Failed to evaluate expression 'ROLE_SUPERVISOR'
就是說(shuō)use-expressions這種表示法是不認(rèn)識(shí)access=”ROLE_USER”這種寫法的,另外,當(dāng)使用了<http use-expressions=”true”>時(shí),一定要在配置中至少有一個(gè)符合use-expressions的表示法,否則就會(huì)報(bào)類似如下錯(cuò)誤:
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'ROLE_SUPERVISOR' cannot be found on object of type 'org.springframework.security.web.access. expression.WebSecurityExpressionRoot'
這個(gè)簡(jiǎn)單的配置例子大概就寫這么多吧,最后說(shuō)說(shuō)我對(duì)Spring Security的看法,我個(gè)人覺得Spring Security的功能的確是很強(qiáng)大,考慮得也非常全面,幾乎什么都想替使用者做完,但正是它的這點(diǎn),我覺得倒是它的缺點(diǎn),在我了解它并配置的過(guò)程中,我 個(gè)人覺得是非常復(fù)雜繁瑣的,而且它現(xiàn)在的文檔支持也并不好,正如上面所看到的一樣,文檔與例子中的寫法都不一致。事實(shí)上,使用者并不希望它什么都做到,比 如它做的那個(gè)缺省登錄頁(yè)面,那個(gè)有意義嗎?使用者比如我,其實(shí)就是希望一個(gè)很簡(jiǎn)單的權(quán)限判斷,比如我打開某一個(gè)鏈接,然后你告訴我訪問(wèn)者有無(wú)權(quán)限訪問(wèn),給 我返回一個(gè)類似true或false的結(jié)果就夠了!至于其他的事情,我是如何的處理后續(xù)過(guò)程并不用Spring Security操心的,但很顯然,子猴認(rèn)為Spring Security在這點(diǎn)上做得并不好。