嚴(yán)格權(quán)限管理說明文檔_第1頁
嚴(yán)格權(quán)限管理說明文檔_第2頁
嚴(yán)格權(quán)限管理說明文檔_第3頁
嚴(yán)格權(quán)限管理說明文檔_第4頁
嚴(yán)格權(quán)限管理說明文檔_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

系統(tǒng)權(quán)限管理

SpringSecurity在認(rèn)識SpringSecurity之前,所有的權(quán)限驗證邏輯都混雜在業(yè)務(wù)邏輯中,用戶的每個操作以前可能都需要對用戶是否有進(jìn)行該項操作的權(quán)限進(jìn)行判斷,來達(dá)到認(rèn)證授權(quán)的目的。類似這樣的權(quán)限驗證邏輯代碼被分散在系統(tǒng)的許多地方,難以維護(hù)。AOP(AspectOrientedProgramming)和SpringSecurity為我們的應(yīng)用程序很好的解決了此類問題,正如系統(tǒng)日志,事務(wù)管理等這些系統(tǒng)級的服務(wù)一樣,我們應(yīng)該將它作為系統(tǒng)一個單獨的“切面”進(jìn)行管理,以達(dá)到業(yè)務(wù)邏輯與系統(tǒng)級的服務(wù)真正分離的目的,SpringSecurity將系統(tǒng)的安全邏輯從業(yè)務(wù)中分離出來。本文代碼運行環(huán)境:JDK6.0spring-framework-2.5.4spring-security-2.0.0JavaEE5Web容器:ApacheTomcat6.0IDE工具:Eclipse3.3+MyEclipse6.5操作系統(tǒng):Linux(Fedora8)這只是我個人的學(xué)習(xí)總結(jié)而已,還請高手們指出本文的不足之處。一SpringSecurity簡介這里提到的SpringSecurity也就是被大家廣為熟悉的AcegiSecurity,2007年底AcegiSecurity正式成為SpringPortfolio項目,并更名為SpringSecurity.SpringSecurity是「-個能夠為基于Spring的企業(yè)應(yīng)用系統(tǒng)提供描述性安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應(yīng)用上下文中配置的Bean,充分利用了SpringIoC(依賴注入,也稱控制反轉(zhuǎn))和AOP(面向切面編程)功能,為應(yīng)用系統(tǒng)提供聲明式的安全訪問控制功能,減少了為企業(yè)系統(tǒng)安全控制編寫大量重復(fù)代碼的工作。通過在許多項目中實踐應(yīng)用以及社區(qū)的貢獻(xiàn),如今的SpringSecurity已經(jīng)成為SpringFramework下最成熟的安全系統(tǒng),它為我們提供了強(qiáng)大而靈活的企業(yè)級安全服務(wù),如:0認(rèn)證授權(quán)機(jī)制0Web資源訪問控制0業(yè)務(wù)方法調(diào)用訪問控制0領(lǐng)域?qū)ο笤L問控制AccessControlList(ACL)0單點登錄(CentralAuthenticationService)

0X509認(rèn)證0信道安全(ChannelSecurity)管理等功能當(dāng)保護(hù)Web資源時,SpringSecurity使用Servlet過濾器來攔截Http請求進(jìn)行身份驗證并強(qiáng)制安全性,以確保WEB資源被安全的訪問。如下圖是SpringSecurity的主要組件圖(摘自《SpringinAction》):圖1SpringSecurity的基本組件無論是保護(hù)WEB資源還是保護(hù)業(yè)務(wù)方法或者領(lǐng)域?qū)ο?,SpringSecurity都的通過上圖中的組件來完成的。本文主要闡述如何使用SpringSecurity對WEB應(yīng)用程序的資源進(jìn)行安全訪問控制,并通過一個簡單的實例來對SpringSecurity提供的各種過濾器的功能和配置方法進(jìn)行描述。保護(hù)Web資源SpringSecurity提供了很多的過濾器,它們攔截Servlet請求,并將這些請求轉(zhuǎn)交給認(rèn)證處理過濾器和訪問決策過濾器進(jìn)行處理,并強(qiáng)制安全性,認(rèn)證用戶身份和用戶權(quán)限以達(dá)到保護(hù)Web資源的目的。對于Web資源我們大約可以只用6個過濾器來保護(hù)我們的應(yīng)用系統(tǒng),下表列出了這些安全過濾器的名稱作用以及它們在系統(tǒng)中的執(zhí)行順序:過濾器作用通道處理過濾器確保請求是在安全通道(HTTP和HTTPS)之上傳輸?shù)恼J(rèn)證處理過濾器接受認(rèn)證請求,并將它們轉(zhuǎn)交給認(rèn)證管理器進(jìn)行身份驗證CAS處理過濾器接受CAS服務(wù)票據(jù),驗證YaleCAS(單點登錄)是否已經(jīng)對用戶進(jìn)行了認(rèn)證HTTP基本授權(quán)過濾器處理使用HTTP基本認(rèn)證的身份驗證請求集成過濾器處理認(rèn)證信息在請求間的存儲(比如在HTTP會話中)安全強(qiáng)制過濾器確保用戶己經(jīng)認(rèn)證,并且滿足訪問一個受保護(hù)Web資源的權(quán)限需求接下來,通過一個實例來說明它們的具體使用方法和如何在Spring中進(jìn)行配置。1建立SpringSecurity項目首先在MyEclipse中創(chuàng)建一個WebProject,并使用MyEclipse工具導(dǎo)入Spring項目的依賴JAR包,并生成默認(rèn)的,這里暫時不會用到這個文件,本文只是通過一個簡單的實例來說明如何配置使用SpringSecurity,不會涉及到數(shù)據(jù)庫,而是使用一個用戶屬性(perties)文件來保存用戶信息(包括用戶名,密碼及相應(yīng)的權(quán)限),但在實際的項目中,我們很少會這樣做,而是應(yīng)該把用戶信息存在數(shù)據(jù)庫中,下一篇文章中將會詳細(xì)介紹并用到這個文件來配置Hibernate,這里我們保留它。現(xiàn)在還需要為項目導(dǎo)入SpringSecurity的JAR包,它沒有包括在SpringFramework中,你可以從/download/下載,并將spring-security-core-2.0.0.jar(這是核心代碼庫)和spring-security-core-tiger-2.0.0.jar(和annotation有關(guān)的,比如使用注解對方法進(jìn)行安全訪問控制,在下一篇中會用到)拷貝到項目的lib目錄下,其中也包括兩個實例(tutorial和contacts),并且兩個實例中都包括了如何使用Spring2.0的命名空間來配置SpringSecurity,無論你對Spring2.0命名空間的使用是否了解,它將使我們的配置文件大大縮短,簡化開發(fā),提高生產(chǎn)效率。到此,我們的SpringSecurity項目就建好了,項目目錄結(jié)構(gòu)如下圖所示:T讓.springsecurfty,盤ST]k十JRE$ystemLibrary[JDK]kS..JavaEE5LibrariesASFleferencedLibraries▼膘WebRootBadmins&db&META-INF:SpringSecurity配置文件&user▼2?WEB-INF▼2?conteKfc".?applicatiohGont&x^mlapplicationCpntext-security.x'ml&lib&”矽用戶信息文件邕1perties團(tuán)web.xmlaccessDenied.jspjdefault.jspj*index.jsp£login.jsp圖2項目目錄結(jié)構(gòu)2配置web.xmlSpringSecurity使用一組過濾器鏈來對用戶進(jìn)行身份驗證和授權(quán)。首先,在web.xml文件中添加FilterToBeanProxy過濾器配置:<filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.security.util.FilterToBeanProxy</filter-class><init-param><param-name>targetClass</param-name><param-value>org.springframework.security.util.FilterChainProxy</param-value></init-param></filter>org.springframework.security.util.FilterToBeanProxy實現(xiàn)了Filter接口,它通過調(diào)用WebapplicationContextUtils類的getWebApplicationnContext(servletContext)方法來獲取Spring的應(yīng)用上下文句柄,并通過getBean(beanName)方法來獲取Spring受管Bean的對象,即這里targetClass參數(shù)配置的Bean,并通過調(diào)用FilterChainProxy的init()方法來啟動SpringSecurity過濾器鏈進(jìn)行各種身份驗證和授權(quán)服務(wù)(FilterChainProxy類也是實現(xiàn)了Filter接口),從而將過濾功能委托給Spring的FilterChainProxy受管Bean(它維護(hù)著一個處理驗證和授權(quán)的過濾器列表,列表中的過濾器按照一定的順序執(zhí)行并完成認(rèn)證過程),這樣即簡化了web.xml文件的配置,又能充分利用Spring的IoC功能來完成這些過濾器執(zhí)行所需要的其它資源的注入。當(dāng)用戶發(fā)出請求,過濾器需要根據(jù)web.xml配置的請求映射地址來攔截用戶請求,這時SpringSecurity開始工作,它會驗證你的身份以及當(dāng)前請求的資源是否與你擁有的權(quán)限相符,從而達(dá)到保護(hù)Web資源的功能,下面是本例所要過濾的用戶請求地址:<filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/j_spring_security_check</url-pattern></filter-mapping><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping>提示:/j_spring_security_check是SpringSecurity默認(rèn)的進(jìn)行表單驗證的過濾地址,你也可以修改為別的名稱,但是需要和applicationContext-security.xml中相對應(yīng),當(dāng)然還會涉及到其它一些默認(rèn)值(可能是一個成員變量,也可能是別的請求地址),在下文我們將看到,建議你在閱讀此文的同時,應(yīng)該參照SpringSecurity項目的源代碼,便于你更好的理解。酉己置applicationContext-security.xml3.1FilterChainProxy過濾器鏈FilterChainProxy會按順序來調(diào)用一組filter,使這些filter即能完成驗證授權(quán)的本質(zhì)工作,又能享用SpringIoc的功能來方便的得到其它依賴的資源。FilterChainProxy配置如下:<beanid="filterChainProxy”class="org.springframework.security.util.FilterChainProxy"><propertyname="filterInvocationDefinitionSource"><value><![CDATA[CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISONPATTERN_TYPE_APACHE_ANT/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor]]></value></property></bean>CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定義URL在匹配之前必須先轉(zhuǎn)為小寫,PATTERN_TYPE_APACHE_ANT定義了使用Apacheant的匹配模式,/**定義的將等號后面的過濾器應(yīng)用在那些URL上,這里使用全部URL過濾,每個過濾器之間都適用逗號分隔,它們按照一定的順序排列。提示:特別需要注意的是,即使你配置了系統(tǒng)提供的所有過濾器,這個過濾器鏈會很長,但是千萬不要使用換行,否則它們不會正常工作,容器甚至不能正常啟動。下面根據(jù)FilterChainProxy的配置來介紹各個過濾器的配置,各個過濾器的執(zhí)行順序如以上配置。首先是通道處理過濾器,如果你需要使用HTTPS,這里我們就使用HTTP進(jìn)行傳輸,所以不需要配置通道處理過濾器,然后是集成過濾器,配置如下:<beanid="httpSessionContextIntegrationFilter”class="org.springframework.security.context.HttpSessionContextIntegrationFilter"/>httpSessionContextIntegrationFilter是集成過濾器的一個實現(xiàn),在用戶的一個請求過程中,用戶的認(rèn)證信息通過SecurityContextHolder(使用ThreadLoacl實現(xiàn))進(jìn)行傳遞的,所有的過濾器都是通過SecurityContextHolder來獲取用戶的認(rèn)證信息,從而在一次請求中所有過濾器都能共享Authentication(認(rèn)證),減少了HttpRequest參數(shù)的傳送,下面的代碼是從安全上下文的獲取Authentication對象的方法:SecurityContextcontext=SecurityContextHolder.getContext();Authenticationauthentication=context.getAuthentication();但是,ThreadLoacl不能跨越多個請求存在,所以,集成過濾器在請求開始時從Http會話中取出用戶認(rèn)證信息并創(chuàng)建一個SecurityContextHolder將Authentication對象保存在其中,在請求結(jié)束之后,在從SecurityContextHolder中獲取Authentication對象并將其放回Http會話中,共下次請求使用,從而達(dá)到了跨越多個請求的目的。集成過濾器還有其它的實現(xiàn),可以參考相關(guān)文檔。提示:集成過濾器必須在其它過濾器之前被使用。logoutFilter(退出過濾器),退出登錄操作:<beanid="logoutFilter”class="org.springframework.security.ui.logout.LogoutFilter"><constructor-argvalue="/index.jsp”/><constructor-arg><list><!--實現(xiàn)了LogoutHandler接口(logout方法)--><refbean="rememberMeServices"/><beanclass="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/></list></constructor-arg></bean>LogoutFilter的構(gòu)造函數(shù)需要兩個參數(shù),第一個是退出系統(tǒng)后系統(tǒng)跳轉(zhuǎn)到的URL,第二個是一個LogoutHandler類型的數(shù)組,這個數(shù)組里的對象都實現(xiàn)了LogoutHandler接口,并實現(xiàn)了它的logout方法,用戶在發(fā)送退出請求后,會一次執(zhí)行LogoutHandler數(shù)組的對象并調(diào)用它們的logout方法進(jìn)行一些后續(xù)的清理操作,主要是從SecurityContextHolder對象中清楚所有用戶的認(rèn)證信息(Authentication對象),將用戶的會話對象設(shè)為無效,這些都時由SecurityContextLogoutHandler來完成。LogoutFilter還會清除Cookie記錄,它由另外一個Bean來完成(RememberMeServices)。<refbean="rememberMeServices"/>標(biāo)記指向了我們另外配置的一個Bean:<beanid="rememberMeServices"class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices”p:key="springsecurity”p:userDetailsService-ref="userDetailsService"/>TokenBasedRememberMeServices繼承自系統(tǒng)的AbstractRememberMeServices抽象類(實現(xiàn)了RememberMeServices和LogoutHandler兩個接口),RememberMeServices接口的loginSuccess方法負(fù)責(zé)在用戶成功登錄之后將用戶的認(rèn)證信息存入Cookie中,這個類在后續(xù)的過濾器執(zhí)行過程中也會被用到。另一個userDetailsService屬性也是指向了我們配置的Bean,它負(fù)責(zé)從數(shù)據(jù)庫中讀取用戶的信息,這個類的詳細(xì)配置將在后面的部分詳細(xì)介紹,這里只是簡單的認(rèn)識一下。過濾器鏈的下個配置的過濾器是authenticationProcessingFilter(認(rèn)證過程過濾器),我們使用它來處理表單認(rèn)證,當(dāng)接受到與filterProcessesUrl所定義相同的請求時它開始工作:<beanid="authenticationProcessingFilter”class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter”p:authenticationManager-ref="authenticationManager”p:authenticationFailureUrl="/login.jsp?login_error=1”p:defaultTargetUrl="/default.jsp”p:filterProcessesUrl="/j_spring_security_check"p:rememberMeServices-ref="rememberMeServices"/>下面列出了認(rèn)證過程過濾器配置中各個屬性的功能:屬性功能authenticationManager認(rèn)證管理器authenticationFailureUrl定義登錄失敗時轉(zhuǎn)向的頁面defaultTargetUrl定義登錄成功時轉(zhuǎn)向的頁面filterProcessesUrl定義登錄請求的地址(在web.xml中配置過)rememberMeServices在驗證成功后添加cookie信息這里也用到了rememberMeServices,如果用戶認(rèn)證成功,將調(diào)用RememberMeServices的loginSuccess方法將用戶認(rèn)證信息寫入Cookie中,這里也可以看到使用IoC的好處。決定用戶是否有權(quán)限訪問受保護(hù)資源的第一步就是要確定用戶的身份,最常用的方式就是用戶提供一個用戶名和密碼以確認(rèn)用戶的身份是否合法,這一步就是由認(rèn)證過程過濾器調(diào)用authenticationManager(認(rèn)證管理器)來完成的。org.springframework.security.AuthenticationManager接口定義了一個authenticate方法,它使用Authentication作為入口參數(shù)(只包含用戶名和密碼),并在驗證成功后返回一個完整的Authentication對象(包含用戶的權(quán)限信息GrantedAuthority數(shù)組對象),authenticationProcessingFilter(認(rèn)證過程過濾器)會將這個完整的Authentication對象存入SecurityContext中,如果認(rèn)證失敗會拋出一個AuthenticationException并跳轉(zhuǎn)到authenticationFailureUrl定義的URL.認(rèn)證管理其配置如下:<beanid="authenticationManager”class="viders.ProviderManager”p:sessionController-ref="concurrentSessionController"><propertyname="providers"><list><refbean="daoAuthenticationProvider"/><beanclass="viders.anonymous.AnonymousAuthenticationProvider”p:key="springsecurity"/><beanclass="viders.rememberme.RememberMeAuthenticationProvider"p:key="springsecurity"/></list></property></bean>正如在配置中看到的一樣,系統(tǒng)使用viders.ProviderManager(提供者管理器)類作為認(rèn)證管理器的一個實現(xiàn),事實上這個類是繼承自實現(xiàn)了AuthenticationManager接口的AbstractAuthenticationManager類。需要注意的是ProviderManager(提供者管理器)自己并不實現(xiàn)身份驗證,而是把這項工作交給了多個認(rèn)證提供者(提供者集合)或者說的多個認(rèn)證來源。提示:SpringSecurity為我們提供的所有認(rèn)證提供者實現(xiàn)都是viders.AuthenticationProvider接口的實現(xiàn)類,它們都實現(xiàn)了此接口的authenticate方法,如果你正在看源代碼,會發(fā)現(xiàn)這個authenticate方法事實上和AuthenticationManager(認(rèn)證管理器)接口的authenticate方法完全一樣。providers屬性定義了提供者管理器的集合,ProviderManager(提供者管理器)逐一遍歷這個認(rèn)證提供者的集合并調(diào)用提供者的authenticate方法,如果一個提供者認(rèn)證失敗會嘗試另外一個提供者直到某一個認(rèn)證提供者能夠成功的驗證該用戶的身份,以保證獲取不同來源的身份認(rèn)證。下面表格列出了系統(tǒng)提供的一些認(rèn)證提供者:提供者作用DaoAuthenticationProvider從數(shù)據(jù)庫中讀取用戶信息驗證身份AnonymousAuthenticationProvider匿名用戶身份認(rèn)證RememberMeAuthenticationProvider已存cookie中的用戶信息身份認(rèn)證AuthByAdapterProvider使用容器的適配器驗證身份CasAuthenticationProvider根據(jù)Yile中心認(rèn)證服務(wù)驗證身份,用于實現(xiàn)單點登陸JaasAuthenticationProvider從JASS登陸配置中獲取用戶信息驗證身份RemoteAuthenticationProvider根據(jù)遠(yuǎn)程服務(wù)驗證用戶身份RunAsImplAuthenticationProvider對身份已被管理器替換的用戶進(jìn)行驗證X509AuthenticationProvider從X509認(rèn)證中獲取用戶信息驗證身份TestingAuthenticationProvider單元測試時使用從上面的表中可以看出,系統(tǒng)為我們提供了不同的認(rèn)證提供者,每個認(rèn)證提供者會對自己指定的證明信息進(jìn)行認(rèn)證,如DaoAuthenticationProvider僅對UsernamePasswordAuthenticationToken這個證明信息進(jìn)行認(rèn)證。在實際項目中,用戶的身份和權(quán)限信息可能存儲在不同的安全系統(tǒng)中(如數(shù)據(jù)庫,LDAP服務(wù)器,CA中心)。作為程序員,我們可以根據(jù)需要選擇不同的AuthenticationProvider(認(rèn)證提供者)來對自己的系統(tǒng)提供認(rèn)證服務(wù)。這里我們著重介紹DaoAuthenticationProvider,它從數(shù)據(jù)庫中讀取用戶信息驗證身份,配置如下:<beanid="daoAuthenticationProvider”class="viders.dao.DaoAuthenticationProvider”p:passwordEncoder-ref="passwordEncoder”p:userDetailsService-ref="userDetailsService"/><beanid="passwordEncoder”class="viders.encoding.Md5PasswordEncoder"/>還記得前面配置的RememberMeServices嗎?它也有一個和DaoAuthenticationProvider同樣的屬性userDetailsService,這是系統(tǒng)提供的一個接口(org.springframework.security.userdetails.UserDetailsService),在這里我們把它單獨提出來進(jìn)行介紹。首先我們需要了解SpringSecurity為我們提供的另外一個重要的組件,org.springframework.security.userdetails.UserDetails接口,它代表一個應(yīng)用系統(tǒng)的用戶,該接口定義與用戶安全信息相關(guān)的方法:StringgetUsername():獲取用戶名;StringgetPassword():獲取密碼;booleanisAccountNonExpired():用戶帳號是否過期;booleanisAccountNonLocked():用戶帳號是否鎖定;booleanisCredentialsNonExpired():用戶的憑證是否過期;booleanisEnabled():用戶是否處于激活狀態(tài)。當(dāng)以上任何一個判斷用戶狀態(tài)的方法都返回false時,用戶憑證就被視為無效。UserDetails接口還定義了獲取用戶權(quán)限信息的getAuthorities()方法,該方法返回一個GrantedAuthority[]數(shù)組對象,GrantedAuthority是用戶權(quán)限信息對象,這個對象中定義了一個獲取用戶權(quán)限描述信息的getAuthority()方法。UserDetails即可從數(shù)據(jù)庫中返回,也可以從其它如LDAP中返回,這取決與你的系統(tǒng)中使用什么來存儲用戶信息和權(quán)限以及相應(yīng)的認(rèn)證提供者。這里我們只重點介紹DaoAuthenticationProvider(從數(shù)據(jù)庫中獲取用戶認(rèn)證信息的提供者),本人水平有限,在項目中還沒有機(jī)會用到其它提供者。說到這里,這個封裝了用戶詳細(xì)信息的UserDetails該從哪兒獲取呢?這就是我們接下來要介紹的UserDetailsService接口,這個接口中只定義了唯一的UserDetailsloadUserByUsername(Stringusername)方法,它通過用戶名來獲取整個UserDetails對象??吹竭@里你可能會有些糊涂,因為前面提到的Authentication對象中也存放了用戶的認(rèn)證信息,需要注意Authentication對象才是SpringSecurity使用的進(jìn)行安全訪問控制用戶信息安全對象。實際上,Authentication對象有未認(rèn)證和已認(rèn)證兩種狀態(tài),在作為參數(shù)傳入認(rèn)證管理器(AuthenticationManager)的authenticate方法時,是一個未認(rèn)證的對象,它從客戶端獲取用戶的身份信息(如用戶名,密碼),可以是從一個登錄頁面,也可以從Cookie中獲取,并由系統(tǒng)自動構(gòu)造成一個Authentication對象。而這里提到的UserDetails代表一個用戶安全信息的源(從數(shù)據(jù)庫,LDAP服務(wù)器,CA中心返回),SpringSecurity要做的就是將這個未認(rèn)證的Authentication對象和UserDetails進(jìn)行匹配,成功后將UserDetails中的用戶權(quán)限信息拷貝到Authentication中組成一個完整的Authentication對象,共其它組件共享。這樣,我們就可以在系統(tǒng)中獲取用戶的相關(guān)信息了,需要使用到Authentication對象定義的ObjectgetPrincipal()方法,這個方法返回一個Object類型的對象,通??梢詫⑺D(zhuǎn)換為UserDetails,從而可以獲取用戶名,密碼以及權(quán)限等信息。代碼如下:UserDetailsdetails=(UserDetails)authentication.getPrincipal();GrantedAuthority[]authority=details.getAuthorities();前面介紹了DaoAuthenticationProvider,它可以從數(shù)據(jù)庫中讀取用戶信息,同樣也可以從一個用戶屬性文件中讀取,下一篇文章中我們在介紹如何從數(shù)據(jù)庫中讀取用戶信息,當(dāng)然還會涉及到更深入的東西,比如根據(jù)自己系統(tǒng)的需要自定義UserDetails和UserDetailsService,這個只是讓你對整個系統(tǒng)有個簡單的了解,所以我們使用用戶屬性文件(perties)來存儲用戶信息:admin=admin,ROLE_SUPERVISORuser1=user1,ROLE_USERuser2=user2,ROLE_USERuser3=user3,disabled,ROLE_USER酉己置userDetailsService:<beanid="userDetailsService”class="org.springframework.security.userdetails.memory.InMemoryDaoImpl"><propertyname="userProperties"><beanclass="org.springframework.beans.factory.config.PropertiesFactoryBean"p:location="/WEB-INF/perties"/></property></bean>InMemoryDaoImpl類是UserDetailsService接口的一個實現(xiàn),它從屬性文件里讀取用戶信息,SpringSecurity使用一個屬性編輯器將用戶信息為我們組織成一個org.springframework.security.userdetails.memory.UserMap類的對象,我們也可以直接為它提供一個用戶權(quán)限信息的列表,詳見applicationContext-security.xml配置文件。UserMap字符串的每一行都用鍵值對的形式表示,前面是用戶名,然后是等號,后面是賦予該用戶的密碼/權(quán)限等信息,它們使用逗號隔開。比如:admin=admin,ROLE_SUPERVISOR定義了一個名為admin的用戶登錄密碼為admin,該用戶擁有ROLE_SUPERVISOR權(quán)限,再如perties文件中配置的名為user3的用戶登錄密碼為user3,該用戶擁有ROLE_USER權(quán)限,disabled定義該用戶不可用,為被激活(UserDetails的isEnabled方法)。即使是系統(tǒng)的開發(fā)者或者說是最終用戶,都不應(yīng)該看到系統(tǒng)中有明文的密碼。所以,SpringSecurity考慮的還是很周到的,為我們提供的密碼加密的功能。正如你在Dao認(rèn)證提供者(DaoAuthenticationProvider)中看到的,passwordEncoder屬性配置的就是一個密碼加密程序(密碼編碼器)。這里我們使用MD5加密,可以看配置文件中的scott用戶,你還能看出他的密碼是什么嗎?當(dāng)然這里只是演示功能,其它用戶還是沒有改變,你可以自己試試。系統(tǒng)為我們提供了一些常用的密碼編碼器(這些編碼器都位于viders.encoding包下):PlaintextPasswordEncoder(默認(rèn))不對密碼進(jìn)行編碼,直接返回未經(jīng)改變的密碼;Md4PasswordEncoder對密碼進(jìn)行消息摘要(MD4)編碼;Md5PasswordEncoder對密碼進(jìn)行消息摘要(MD5)編碼;ShaPasswordEncoder對密碼進(jìn)行安全哈希算法(SHA)編碼。你可以根據(jù)需要選擇合適的密碼編碼器,你也可以設(shè)置編碼器的種子源(saltsource)。一個種子源為編碼提供種子(salt),或者稱編碼的密鑰,這里不再贅述。這里附加介紹了不少東西,希望你還沒有忘記在AuthenticationManager(認(rèn)證管理器)中還配置了一個名為sessionController的Bean,這個Bean可以阻止用戶在進(jìn)行了一次成功登錄以后在進(jìn)行一次成功的登錄。在applicationContext-security.xml配置文件添加sessionController的配置:<beanid="concurrentSessionController"class="org.springframework.security.concurrent.ConcurrentSessionControllerImpl”p:maximumSessions="1”p:exceptionIfMaximumExceeded="true"p:sessionRegistry-ref="sessionRegistry"/><beanid="sessionRegistry”class="org.springframework.security.concurrent.SessionRegistryImpl"/>maximumSessions屬性配置了只允許同一個用戶登錄系統(tǒng)一次,exceptionIfMaximumExceeded屬性配置了在進(jìn)行第二次登錄是是否讓第一次登錄失效。這里設(shè)置為true不允許第二次登錄。要讓此功能生效,我們還需要在web.xml文件中添加一個監(jiān)聽器,以讓SpringSecurity能獲取Session的生命周期事件,配置如下:<listener><listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class></listener>HttpSessionEventPublisher類實現(xiàn)javax.servlet.http.HttpSessionListener接口,在Session被創(chuàng)建的時候通過調(diào)用ApplicationContext的publishEvent(ApplicationEventevent)發(fā)布HttpSessionCreatedEvent類型的事件,HttpSessionCreatedEvent類繼承自org.springframework.context.ApplicationEvent類的子類HttpSessionApplicationEvent抽象類。concurrentSessionController使用sessionRegistry來完成對發(fā)布的Session的生命周期事件的處理,org.springframework.security.concurrent.SessionRegistryImpl(實現(xiàn)了SessionRegistry接口),SessionRegistryImpl類還實現(xiàn)了SpringFramework的事件監(jiān)聽org.springframework.context.ApplicationListener接口,并實現(xiàn)了該接口定義的onApplicationEvent(ApplicationEventevent)方法用于處理ApplicationEvent類型的事件,如果你了解SpringFramework的事件處理,那么這里你應(yīng)該可以很好的理解。認(rèn)證管理器到此介紹完畢了,認(rèn)證過程過濾器也介紹完了,接下來我們繼續(xù)介紹過濾器鏈的下一個過濾器securityContextHolderAwareRequestFilter:<beanid="securityContextHolderAwareRequestFilter"class="org.springframework.security.wrapper.SecurityContextHolderAvareRequestFilter"/>這個過濾器使用裝飾模式(DecorateModel),裝飾的HttpServletRequest對象。其Wapper是ServletRequest包裝類HttpServletRequestWrapper的子類(如SavedRequestAwareWrapper或SecurityContextHolderAwareRequestWrapper),附上獲取用戶權(quán)限信息,request參數(shù),headers和cookies的方法。rememberMeProcessingFilter過濾器配置:<beanid="rememberMeProcessingFilter"class="org.springframework.security.ui.rememberme.RememberMeProcessingFilter”p:authenticationManager-ref="authenticationManager”p:rememberMeServices-ref="rememberMeServices"/>當(dāng)SecurityContextHolder中不存在Authentication用戶授權(quán)信息時,rememberMeProcessingFilter就會調(diào)用rememberMeServices的autoLogin()方法從cookie中獲取用戶信息自動登錄。anonymousProcessingFilter過濾器配置:<beanid="anonymousProcessingFilter”class="viders.anonymous.AnonymousProcessingFilter”p:key="springsecurity”p:userAttribute="anonymousUser,ROLE_ANONYMOUS"/>如果不存在任何授權(quán)信息時,自動添加匿名用戶身份至SecurityContextHolder中,就是這里配置的userAttribute,系統(tǒng)為用戶分配一個ROLE_ANONYMOUS權(quán)限。exceptionTranslationFilter(異常處理過濾器),該過濾器用來處理在系統(tǒng)認(rèn)證授權(quán)過程中拋出的異常,主要是處理AccessDeniedException和AuthenticationException兩個異常并根據(jù)配置跳轉(zhuǎn)到不同URL:<beanid="exceptionTranslationFilter"class="org.springframework.security.ui.ExceptionTranslationFilter”p:accessDeniedHandler-ref="accessDeniedHandler”p:authenticationEntryPoint-ref="authenticationEntryPoint"/><!--處理AccessDeniedException--><beanid="accessDeniedHandler”class="org.springframework.security.ui.AccessDeniedHandlerImpl”p:errorPage="/accessDenied.jsp"/><beanid="authenticationEntryPoint”class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint”p:loginFormUrl="/login.jsp”p:forceHttps="false"/>accessDeniedHandler用于處理AccessDeniedException異常,當(dāng)用戶沒有權(quán)限訪問當(dāng)前請求的資源時拋出此異常,并跳轉(zhuǎn)自這里配置的/accessDenied.jsp頁面。authenticationEntryPoint(認(rèn)證入口點),這里定義了用戶登錄的頁面。系統(tǒng)為我們提供3個認(rèn)證入口點的實現(xiàn):認(rèn)證入口點作用BasicProcessingFilterEntryPoint通過向瀏覽器發(fā)送一個HTTP401(未授權(quán))消息,由瀏覽器彈出登錄對話框,提示用戶登錄AuthenticationProcessingFilterEntryPoint將用戶重定向到一個基于HTML表單的登錄頁面CasProcessingFilterEntryPoint將用戶重定向至一個YaleCAS登錄頁面這里我們使用AuthenticationProcessingFilterEntryPoint認(rèn)證入口點,提供給用戶一個友好的登錄界面,只是為了給用戶更好的體驗。filterSecurityInterceptor(過濾器安全攔截器),該過濾器首先調(diào)用認(rèn)證管理器來判斷用戶是否已被成功驗證,如果沒有被驗證則重定向到登錄界面。否則,從Authentication獲取用戶的權(quán)限信息,然后從objectDefinitionSource中獲取URL所對應(yīng)的權(quán)限,最后調(diào)用accessDecisionManager(訪問決策管理器)來判斷用戶當(dāng)前擁有的權(quán)限是否與當(dāng)前受保護(hù)的URL資源對應(yīng)的權(quán)限匹配,如果匹配就可以訪問該URL資源,否則將拋出AccessDeniedException異常并返回客戶端瀏覽器一個403錯誤(如果用戶定義了accessDenied頁面則會被重定向到該頁,見:異常處理過濾器exceptionTranslationFilter中配置的accessDeniedHandlerBean),訪問決策管理的的工作機(jī)制將在隨后更詳細(xì)介紹,這里先給出過濾器安全攔截器的配置如下:<beanid="filterSecurityInterceptor”class="ercept.web.FilterSecurityInterceptor”p:authenticationManager-ref="authenticationManager”p:accessDecisionManager-ref="accessDecisionManager"><propertyname="objectDefinitionSource"><value><![CDATA[CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISONPATTERN_TYPE_APACHE_ANT/admins/**=ROLE_SUPERVISOR/user/**=ROLE_USER,IS_AUTHENTICATED_REMEMBERED/default.jsp=ROLE_USER,IS_AUTHENTICATED_REMEMBERED/**=IS_AUTHENTICATED_ANONYMOUSLY]]></value></property></bean>從配置可以看出來,過濾器安全攔截器用到了我們前面配置的認(rèn)證管理器,過濾器安全攔截器使用authenticationManager并調(diào)用它的providers(提供者列表)來對用戶的身份進(jìn)行驗證并獲取用戶擁有的權(quán)限。如果用戶被成功認(rèn)證,過濾器安全攔截器將會使用accessDecisionManager(訪問決策管理器)來判斷已認(rèn)證的用戶是否有權(quán)限訪問受保護(hù)的資源,這些受保護(hù)的資源由objectDefinitionSource屬性定義。訪問決策管理器(accessDecisionManager):<beanid="accessDecisionManager”class="org.springframework.security.vote.AffirmativeBased”p:allowIfAllAbstainDecisions="false"><propertyname="decisionV)ters"><list><beanclass="org.springframework.security.vote.RoleV)ter”/><beanclass="org.springframework.security.vote.AuthenticatedVoter"/></list></property></bean>SpringSecurity安全機(jī)制的第一步,訪問決策管理器驗證用戶是否有權(quán)限訪問相應(yīng)的資源(filterSecurityInterceptor中objectDefinitionSource屬性定義的訪問URL需要的屬性信息)。org.springframework.security.AccessDecisionManager接口定義了用于驗證用戶是否有權(quán)限訪問受保護(hù)資源的decide方法,另一個supports方法根據(jù)受保護(hù)資源的配置屬性(即訪問這些資源所需的權(quán)限)來判斷該訪問決策管理器是否能做出針對該資源的訪問決策。decide方法最終決定用戶有無訪問權(quán)限,如果沒有則拋出AccessDeniedException異常(面前也提到過,你應(yīng)該在回過頭去看看)。與認(rèn)證管理器類似,訪問決策管理器也不是由自己來實現(xiàn)訪問控制的,而是通過一組投票

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論