Spring Security 3.0須要Java 5.0運行時環境或更高版本。因爲Spring Security的目標是以獨立的方式運行,因此沒有必要將任何特殊的配置文件放入Java運行時環境中。特別是,不須要配置特殊的Java身份驗證和受權服務(JAAS)策略文件,也不須要將Spring Security放在公共的類路徑位置。html
一樣,若是您使用的是EJB容器或Servlet容器,就不須要在任何地方放置任何特殊的配置文件,也不須要在服務器類加載器中包含Spring Security。全部必需的文件都將包含在您的應用程序中。web
這種設計提供了最大的部署時間靈活性,由於您能夠簡單地將您的目標工件(不管是JAR、WAR仍是EAR)從一個系統複製到另外一個系統,它將當即工做。spring
在Spring Security 3.0中,spring-security-core jar的內容被剝離到最低限度。它再也不包含任何與網絡應用安全、LDAP或命名空間配置相關的代碼。咱們將在這裏看一看核心模塊中的一些Java類型。它們表明框架的構建塊,因此若是您須要簡單的名稱空間配置,那麼理解它們是什麼很重要,即便您實際上不須要直接與它們交互。數據庫
最基本的對象是SecurityContextHolder(安全上下文持有者)。咱們在這裏存儲應用程序當前安全上下文的詳細信息,包括當前使用該應用程序的主體的詳細信息。默認狀況下,SecurityContextHolder使用ThreadLocal來存儲這些細節,這意味着安全上下文始終對同一執行線程中的方法可用,即便安全上下文沒有做爲參數顯式傳遞給這些方法。這種狀況下使用ThreadLocal是很是安全的,只要記得在處理完當前主體的請求之後,把這個線程清除就好了。固然,Spring Security自動幫你管理這一切了, 你就不用擔憂什麼了。小程序
有些程序並不適合使用ThreadLocal,由於它們處理線程的特殊方法。好比Swing客戶端也許但願Java Virtual Machine裏全部的線程 都使用同一個安全環境。SecurityContextHolder能夠在啓動時配置策略,以指定您但願如何存儲上下文。對於獨立的應用程序,您可使用SecurityContextHolderSecurityContextHolder能夠在啓動時配置策略,以指定您但願如何存儲上下文。對於獨立的應用程序,您可使用SecurityContextHolder.MODE_GLOBAL策略。其餘程序可能也想由安全線程產生的線程也承擔一樣的安全標識。這是經過使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL實現。第一個是設置系統屬性,第二個是調用SecurityContextHolder的靜態方法。大多數應用程序不須要修改默認值,可是若是你想要修改,能夠看一下SecurityContextHolder的JavaDocs中的詳細信息瞭解更多。數組
在SecurityContextHolder中,咱們存儲當前與應用程序交互的主體的詳細信息。Spring Security使用一個身份驗證對象來表示這些信息。您一般不須要本身建立身份驗證對象,可是用戶查詢身份驗證對象是很常見的。您能夠從應用程序中的任何位置使用如下代碼塊來獲取當前通過身份驗證的用戶的名稱,例如:瀏覽器
調用getContext()返回的對象是SecurityContext接口的一個實例。這是保存在線程本地存儲中的對象。正如咱們將在下面看到的,Spring Security中的大多數身份驗證機制都返回一個UserDetails實例做爲主體。緩存
從上面的代碼片斷中須要注意的另外一點是,您能夠從身份驗證對象中獲取一個主體。主體只是一個客體。大多數狀況下,這能夠轉換成一個UserDetails對象。UserDetails是Spring安全的核心接口。它表明一個主體,可是以一種可擴展的和特定於應用程序的方式。將UserDetails視爲您本身的用戶數據庫和SecurityContextHolder內部的Spring Security須要之間的適配器。做爲來自您本身的用戶數據庫的表示,您常常會將UserDetails轉換爲您的應用程序提供的原始對象,所以您能夠調用特定於業務的方法(如getEmail(),getEmployeeNumber(),等等)。安全
如今你可能想知道,我何時提供一個用戶詳細信息對象?我怎麼作呢?我想你說這個東西是聲明式的,我不須要寫任何代碼——什麼給出了?服務器
簡而言之,有一個叫作UserDetailsService(用戶詳細服務)的特殊接口。此接口上的惟一方法接受基於字符串的用戶名參數並返回UserDetails(用戶詳細信息):
這是在Spring Security中爲用戶加載信息的最多見的方法,當須要關於用戶的信息時,您會在整個框架中看到它的使用。
在成功的身份驗證中,UserDetails(用戶詳細信息)用於構建存儲在SecurityContextHolder中的Authentication(身份驗證對象)(下面將詳細介紹)。好消息是咱們提供了大量的用戶細節服務實現,包括一個使用內存映射(InMemoryDaoImpl)的實現和一個使用JDBC (JdbcDaoImpl)的實現。然而,大多數用戶傾向於編寫本身的代碼,他們的實現一般只是簡單地位於表明他們的僱員、客戶或應用程序的其餘用戶的現有數據訪問對象(DAO)之上。請記住,不管您的UserDetailsService返回什麼,均可以使用上面的代碼片斷從安全上下文持有者得到。
關於UserDetailsService常常會有一些混淆。它純粹是用戶數據的DAO,除了向框架內的其餘組件提供數據以外,不執行其餘功能。特別是,它不會對用戶進行身份驗證,這是由AuthenticationManager完成的。在許多狀況下,若是須要自定義身份驗證過程,直接實現AuthenticationProvider更有意義。
除了主體,身份驗證提供的另外一個重要方法是getAuthorities()。這個方法提供了一個受權對象的數組。絕不奇怪,受權是授予委託人的權力。這種權限一般是「角色」,例如ROLE_ADMINISTRATOR或ROLE _ HR _ SUPERVISOR。這些角色稍後將針對web受權、方法受權和域對象受權進行配置。Spring Security的其餘部分可以解釋這些權限,並指望它們存在。受權對象一般由UserDetailsService加載。
一般授予的權限對象是應用程序範圍的權限。它們並不特定於給定的域對象。所以,您不太可能擁有受權來表示對僱員對象編號54的權限,由於若是有成千上萬個這樣的權限,您將很快耗盡內存(或者至少致使應用程序花很長時間來驗證用戶)。固然,Spring Security是專門爲處理這種常見需求而設計的,可是您可使用項目的域對象安全功能來實現這一目的。
簡單回顧一下,目前爲止咱們看到的Spring Security的主要構建模塊是:
SecurityContextHolder,提供對SecurityContext的訪問。
SecurityContext,用於保存Authentication和可能的特定於請求的安全信息。
Authentication,以Spring安全特定的方式表明主體。
GrantedAuthority,以反映授予主體的應用程序範圍的權限。
UserDetails,提供必要的信息,以便從應用程序的DAOs或其餘安全數據源構建身份驗證對象。
UserDetailsService,當傳入基於字符串的用戶名(或證書標識等)時建立UserDetails。
如今您已經瞭解了這些重複使用的組件,讓咱們更仔細地看看身份驗證的過程。
Spring Security能夠參與許多不一樣的身份驗證環境。雖然咱們建議人們使用Spring Security進行身份驗證,而不要與現有的容器管理身份驗證集成,可是它仍然受到支持,就像與您本身的專有身份驗證系統集成同樣。
讓咱們考慮一個你們都熟悉的標準身份驗證場景。
一、提示用戶輸入用戶名和密碼進行登陸。
二、系統(成功)驗證用戶名的密碼是否正確。
三、獲取該用戶的上下文信息(他們的角色列表等等)。
四、爲用戶創建安全上下文。
五、用戶繼續執行一些操做,這些操做可能受到訪問控制機制的保護,該機制根據當前的安全上下文信息檢查操做所需的權限。
前三項構成了身份驗證過程,所以咱們將看看這些是如何在Spring Security中發生的。
一、用戶名和密碼被獲取並組合到一個UsernamePasswordAuthenticationToken的實例中(這是咱們前面看到的身份驗證接口的一個實例)。
二、令牌被傳遞給AuthenticationManager的一個實例進行驗證。
三、AuthenticationManager在身份驗證成功時返回徹底填充的Authentication。
四、經過調用securitycontextholder . GetContext()來創建安全上下文。設置身份驗證(…),傳入返回的身份驗證對象。
從這一點上來看,用戶被認爲是被驗證的。讓咱們看看一些代碼做爲一個例子:
這裏,咱們編寫了一個小程序,要求用戶輸入用戶名和密碼,並執行上面的序列。咱們在這裏實現的身份驗證管理器將驗證用戶名和密碼相同的任何用戶。它爲每一個用戶分配一個角色。上面的輸出將相似於:
請注意,你一般不須要寫任何這樣的代碼。這個過程一般會發生在內部,以一個web認證過濾器爲例,咱們剛剛在這裏的代碼顯示,在Spring Security中到底是什麼構成了驗證的問題,有一個相對簡單的答案。用戶驗證時,SecurityContextHolder包含一個徹底填充的Authentication對象的用戶進行身份驗證。
默認狀況下,使用StrictHttpFirewall。該實現拒絕看似惡意的請求。若是它對你的需求來講太嚴格,那麼你能夠定製什麼類型的請求被拒絕。然而,重要的是你要知道這可能會使你的應用程序受到攻擊。例如,若是您但願利用Spring MVC的矩陣變量,能夠在XML中使用如下配置:
一樣的事情也能夠經過Java配置來實現,方法是公開一個StrictHttpFirewall bean。
事實上,Spring Security並不介意如何將身份驗證對象(Authentication)放入SecurityContextHolder中。惟一關鍵的要求是SecurityContextHolder包含一個身份驗證(Authentication),該身份驗證在抽象安全接口(AbstractSecurityInterceptor)(咱們將在後面詳細討論)須要受權用戶操做以前表明一個主體。
您能夠(許多用戶也能夠)編寫本身的過濾器或MVC控制器,以提供與不基於Spring安全的身份驗證系統的互操做性。例如,您可能正在使用容器管理的身份驗證,這使得當前用戶能夠從線程本地或JNDI位置訪問。或者,你可能在一家擁有傳統專有認證系統的公司工做,這是一個你幾乎沒法控制的公司「標準」。在這種狀況下,很容易讓Spring Security工做,而且仍然提供受權功能。您須要作的只是編寫一個過濾器(或等效工具),從一個位置讀取第三方用戶信息,構建一個Spring安全特定的身份驗證對象(Authentication),並將其放入安全上下文持有者(SecurityContextHolder)。在這種狀況下,您還須要考慮一般由內置身份驗證基礎結構自動處理的事情。例如,在向客戶端腳註寫入響應以前,您可能須要先建立一個HTTP會話來緩存請求之間的上下文:一旦提交了響應,就不可能建立會話。
若是您想知道AuthenticationManager是如何在實際示例中實現的,咱們將在覈心服務一章( core services chapter)中討論這一點。
如今讓咱們探討一下在web應用程序中使用Spring Security的狀況(沒有啓用web.xml安全性)。如何對用戶進行身份驗證並創建安全上下文?
考慮一個典型的web應用程序的身份驗證過程:
一、你訪問主頁,點擊一個連接。
二、一個請求到達服務器,服務器決定您已經請求了一個受保護的資源。
三、因爲您目前沒有經過身份驗證,服務器會發回一個響應,指示您必須經過身份驗證。該響應或者是一個HTTP響應代碼,或者是一個到特定網頁的重定向。
四、根據身份驗證機制,您的瀏覽器要麼重定向到特定的網頁以便您填寫表單,要麼瀏覽器以某種方式檢索您的身份(經過基自己份驗證對話框、cookie、X.509證書等)。)。
五、瀏覽器將向服務器發回響應。這要麼是一個包含您填寫的表單內容的HTTP POST,要麼是一個包含您的身份驗證詳細信息的HTTP標頭。
六、接下來,服務器將決定呈現的憑證是否有效。若是它們是有效的,下一步就會發生。若是無效,一般你的瀏覽器會被要求再試一次(因此你回到上面的第二步)。
七、將重試您爲致使身份驗證過程而提出的原始請求。但願你已經經過了足夠的受權來訪問受保護的資源。若是您有足夠的訪問權限,請求將會成功。不然,您將收到一個返回的HTTP錯誤代碼403,這意味着「禁止」。
Spring Security有不一樣的類來負責上面描述的大部分步驟。主要參與者(按使用順序)是異常轉換過濾器(ExceptionTranslationFilter),一個AuthenticationEntryPoint和一個「身份驗證機制(authentication mechanism)」,負責調用咱們在上一節中看到的AuthenticationManager。
ExceptionTranslationFilter是一個Spring安全篩選器,負責檢測引起的任何Spring安全異常。這種異常一般會被抽象安全接口(AbstractSecurityInterceptor)拋出,它是受權服務的主要提供者。咱們將在下一節討論抽象安全接口,可是如今咱們只須要知道它產生了Java異常,而且對HTTP或者如何驗證主體一無所知。相反,ExceptionTranslationFilter提供此服務,具體負責返回錯誤代碼403(若是主體已通過身份驗證,所以缺乏足夠的訪問權限,如上面的步驟七),或者啓動AuthenticationEntryPoint(若是主體還沒有經過身份驗證,所以咱們須要開始步驟三)。
AuthenticationEntryPoint負責上述列表中的第三步。能夠想象,每一個web應用程序都有一個默認的身份驗證策略(能夠像Spring Security中的其餘任何東西同樣進行配置,可是如今讓咱們保持簡單)。每一個主要的身份驗證系統都有本身的AuthenticationEntryPoint實現,它一般執行步驟3中描述的操做之一。
一旦您的瀏覽器提交了您的身份驗證憑據(或者做爲一個HTTP表單帖子,或者做爲一個HTTP頭),服務器上就須要有一些東西來「收集」這些身份驗證的詳細信息。到如今爲止,咱們已經在上面列表的第六步了。在Spring Security中,咱們爲從用戶代理(一般是web瀏覽器)收集身份驗證詳細信息的功能起了一個特殊的名字,將其稱爲「身份驗證機制(authentication mechanism)」。例如基於表單的登陸和基自己份驗證。一旦從用戶代理收集了身份驗證詳細信息,就會構建一個身份驗證(Authentication)「請求」對象,而後呈現給身份驗證管理器(AuthenticationManager)。
在身份驗證機制收到徹底填充的身份驗證(Authentication)對象後,它將認爲請求有效,將身份驗證(Authentication)放入SecurityContextHolder中,並重試原始請求(上面的第七步)。另外一方面,若是AuthenticationManager拒絕了請求,身份驗證機制將要求用戶代理重試(上面的第二步)。
根據應用程序的類型,可能須要一個策略來存儲用戶操做之間的安全上下文。在典型的web應用程序中,用戶登陸一次,隨後由他們的會話Id標識。服務器緩存持續會話的主體信息。在Spring Security中,在請求之間存儲SecurityContext的責任屬於SecurityContextPersistenceFilter,默認狀況下,它將上下文存儲爲HTTP請求之間的HTTP會話屬性。它將每一個請求的上下文還原到SecurityContextHolder,而且在請求完成時清除SecurityContextHolder。出於安全目的,您不該該直接與HttpSession交互。這樣作是沒有任何理由的——老是使用SecurityContextHolder。
許多其餘類型的應用程序(例如,無狀態的RESTful web服務)不使用HTTP會話,而且會在每次請求時從新進行身份驗證。可是,鏈中包含securitycontextPersistenceFilter仍然很重要,以確保每次請求後都清除了SecurityContextHolder。
在單個會話中接收併發請求的應用程序中,同一安全上下文實例將在線程之間共享。即便正在使用線程本地,它也是從每一個線程的HttpSession中檢索的同一個實例。若是您但願臨時更改線程運行的上下文,這是有意義的。若是您只使用securitycontextholder . GetContext(),並對返回的上下文對象調用設置身份驗證(anAuthentication),則身份驗證對象將在共享同一個SecurityContext實例的全部併發線程中更改。您能夠自定義securitycontextPersistenceFilter的行爲,爲每一個請求建立一個全新的SecurityContext,防止一個線程中的更改影響另外一個線程。或者,您能夠在臨時更改上下文的位置建立一個新實例。方法securitycontextholder . createemptycontext()老是返回一個新的上下文實例。
在Spring Security中,負責作出訪問控制決策的主要接口是訪問決策管理器(AccessDecisionManager)。它有一個decide方法,它須要一個Authentication對象請求訪問、一個"secure object"(安全對象)(見下文)和安全元數據屬性的列表適用的對象(例如授予訪問所需的角色列表)。
若是你熟悉AOP,你會意識到有不一樣類型的建議可用:以前,以後,拋出和周圍。循環建議很是有用,由於advisorSpring Security爲方法調用和web請求提供了一個全面的建議。咱們使用Spring的標準AOP支持實現了方法調用的循環建議,並使用標準過濾器實現了web請求的循環建議。能夠選擇是否繼續方法調用、是否修改響應以及是否拋出異常。
對於那些不熟悉AOP的人來講,須要理解的關鍵一點是,Spring安全性能夠幫助您保護方法調用和web請求。多數人對保護他們服務層上的方法調用感興趣。這是由於服務層是當前一代Java EE應用程序中大多數業務邏輯所在的地方。若是您只須要保護服務層中的方法調用,Spring的標準AOP就足夠了。若是您須要直接保護域對象,您可能會發現AspectJ是值得考慮的。
您能夠選擇使用AspectJ或Spring AOP來執行方法受權,也能夠選擇使用過濾器來執行web請求受權。你能夠同時使用零、1、二或三種方法。主流的使用模式是執行一些web請求受權,再加上服務層上的一些Spring AOP方法調用受權。
那麼什麼是「安全對象」?Spring Security使用該術語來指代任何能夠應用安全性(例如受權決策)的對象。最多見的例子是方法調用和web請求。
每一個受支持的安全對象類型都有本身的攔截器類,它是抽象安全攔截器(AbstractSecurityInterceptor)的子類。重要的是,在調用抽象安全攔截器(AbstractSecurityInterceptor)時,若是主體已通過身份驗證,安全上下文持有者(SecurityContextHolder)將包含有效的身份驗證(Authentication)。
抽象安全攔截器(AbstractSecurityInterceptor)爲處理安全對象請求提供了一致的工做流,一般:
一、查找與當前請求相關聯的「配置屬性」。
二、將安全對象、當前身份驗證和配置屬性提交給訪問決策管理器(AccessDecisionManager)進行受權決策。
三、有可能在調用的過程當中,對Authentication進行修改。
四、容許安全對象調用繼續進行(假設授予了訪問權限)。
五、調用返回後,調用AfterInvocationManager(若是已配置)。若是調用引起了異常,將不會調用AfterInvocationManager。
一個"配置屬性"能夠看作是一個字符串,它對於AbstractSecurityInterceptor使用的類是有特殊含義的。它們由框架中的接口ConfigAttribute表示。它們多是簡單的角色名,也可能有更復雜的含義,這取決於AccessDecisionManager實現的複雜程度。AbstractSecurityInterceptor配置有一個安全數據源(SecurityMetadataSource),用於查找安全對象的屬性。一般這種配置對用戶是隱藏的。配置屬性將做爲安全方法上的註釋或安全網址上的訪問屬性輸入。例如,當咱們在名稱空間介紹中看到相似< intercept-url pattern='/secure/**' access='ROLE_A,ROLE_B'/>的內容時,這意味着配置屬性ROLE_A和ROLE_B適用於與給定模式匹配的web請求。實際上,使用默認的訪問決策管理器(AccessDecisionManager)配置,這意味着任何擁有與這兩個屬性之一匹配的受權(GrantedAuthority)的人都將被容許訪問。嚴格地說,它們只是屬性,解釋依賴於AccessDecisionManager的實現。前綴ROLE_的使用是一個標記,表示這些屬性是角色,應該由Spring Security的RoleVoter使用。只有在使用基於投票者的訪問決策管理器(AccessDecisionManager)時,這纔是相關的。咱們將在受權一章中看到如何實現AccessDecisionManager。
假設AccessDecisionManager決定容許執行這個請求,AbstractSecurityInterceptor會正常執行這個請求。話雖如此,在極少數狀況下,用戶可能但願用不一樣的身份驗證來替換安全上下文(SecurityContext)中的身份驗證(Authentication),該身份驗證由調用運行管理器(RunAsManager)的訪問決策管理器(AccessDecisionManager)來處理。
在至關不常見的狀況下,例如服務層方法須要調用遠程系統並顯示不一樣的標識時,這可能頗有用。 因爲Spring Security會自動將安全身份從一臺服務器傳播到另外一臺服務器(假設您使用的是正確配置的RMI或HttpInvoker遠程協議客戶端),所以這頗有用。
在安全對象調用繼續進行以後,而後返回-這可能意味着方法調用完成或過濾器鏈繼續進行-AbstractSecurityInterceptor得到了處理調用的最後機會。在此階段,AbstractSecurityInterceptor對可能修改返回對象感興趣。 咱們可能但願發生這種狀況,由於沒法在安全對象調用的「途中」作出受權決定。因爲高度可插拔,AbstractSecurityInterceptor會將控制權傳遞給AfterInvocationManager,以根據須要實際修改對象。 此類甚至能夠徹底替換對象,或者引起異常,也能夠按照其選擇的任何方式對其進行更改。調用後檢查僅在調用成功的狀況下執行。 若是發生異常,將跳過其餘檢查。圖9.1「安全攔截器和「安全對象」模型」中顯示了AbstractSecurityInterceptor及其相關對象。
只有考慮一種全新的攔截和受權請求方式的開發人員才須要直接使用安全對象。例如,能夠構建一個新的安全對象來保護對消息傳遞系統的調用。任何須要安全性而且提供攔截調用方式的東西(好比關於建議語義的AOP)都可以被作成一個安全的對象。儘管如此,大多數Spring應用程序將簡單地使用當前支持的三種安全對象類型(AOP聯盟方法定位、AspectJ鏈接點和web請求過濾器調用),而且徹底透明。
那麼什麼是「安全對象」?Spring Security使用該術語來指代任何能夠應用安全性(例如受權決策)的對象。最多見的例子是方法調用和web請求。
每一個受支持的安全對象類型都有本身的攔截器類,它是抽象安全攔截器(AbstractSecurityInterceptor)的子類。重要的是,在調用抽象安全攔截器(AbstractSecurityInterceptor)時,若是主體已通過身份驗證,安全上下文持有者(SecurityContextHolder)將包含有效的身份驗證(Authentication)。
抽象安全攔截器(AbstractSecurityInterceptor)爲處理安全對象請求提供了一致的工做流,一般:
一、查找與當前請求相關聯的「配置屬性」。
二、將安全對象、當前身份驗證和配置屬性提交給訪問決策管理器(AccessDecisionManager)進行受權決策。
三、有可能在調用的過程當中,對Authentication進行修改。
四、容許安全對象調用繼續進行(假設授予了訪問權限)。
五、調用返回後,調用AfterInvocationManager(若是已配置)。若是調用引起了異常,將不會調用AfterInvocationManager。
一個"配置屬性"能夠看作是一個字符串,它對於AbstractSecurityInterceptor使用的類是有特殊含義的。它們由框架中的接口ConfigAttribute表示。它們多是簡單的角色名,也可能有更復雜的含義,這取決於AccessDecisionManager實現的複雜程度。AbstractSecurityInterceptor配置有一個安全數據源(SecurityMetadataSource),用於查找安全對象的屬性。一般這種配置對用戶是隱藏的。配置屬性將做爲安全方法上的註釋或安全網址上的訪問屬性輸入。例如,當咱們在名稱空間介紹中看到相似< intercept-url pattern='/secure/**' access='ROLE_A,ROLE_B'/>的內容時,這意味着配置屬性ROLE_A和ROLE_B適用於與給定模式匹配的web請求。實際上,使用默認的訪問決策管理器(AccessDecisionManager)配置,這意味着任何擁有與這兩個屬性之一匹配的受權(GrantedAuthority)的人都將被容許訪問。嚴格地說,它們只是屬性,解釋依賴於AccessDecisionManager的實現。前綴ROLE_的使用是一個標記,表示這些屬性是角色,應該由Spring Security的RoleVoter使用。只有在使用基於投票者的訪問決策管理器(AccessDecisionManager)時,這纔是相關的。咱們將在受權一章中看到如何實現AccessDecisionManager。
假設AccessDecisionManager決定容許執行這個請求,AbstractSecurityInterceptor會正常執行這個請求。話雖如此,在極少數狀況下,用戶可能但願用不一樣的身份驗證來替換安全上下文(SecurityContext)中的身份驗證(Authentication),該身份驗證由調用運行管理器(RunAsManager)的訪問決策管理器(AccessDecisionManager)來處理。
在至關不常見的狀況下,例如服務層方法須要調用遠程系統並顯示不一樣的標識時,這可能頗有用。 因爲Spring Security會自動將安全身份從一臺服務器傳播到另外一臺服務器(假設您使用的是正確配置的RMI或HttpInvoker遠程協議客戶端),所以這頗有用。
在安全對象調用繼續進行以後,而後返回-這可能意味着方法調用完成或過濾器鏈繼續進行-AbstractSecurityInterceptor得到了處理調用的最後機會。在此階段,AbstractSecurityInterceptor對可能修改返回對象感興趣。 咱們可能但願發生這種狀況,由於沒法在安全對象調用的「途中」作出受權決定。因爲高度可插拔,AbstractSecurityInterceptor會將控制權傳遞給AfterInvocationManager,以根據須要實際修改對象。 此類甚至能夠徹底替換對象,或者引起異常,也能夠按照其選擇的任何方式對其進行更改。調用後檢查僅在調用成功的狀況下執行。 若是發生異常,將跳過其餘檢查。圖9.1「安全攔截器和「安全對象」模型」中顯示了AbstractSecurityInterceptor及其相關對象。
只有考慮一種全新的攔截和受權請求方式的開發人員才須要直接使用安全對象。例如,能夠構建一個新的安全對象來保護對消息傳遞系統的調用。任何須要安全性而且提供攔截調用方式的東西(好比關於建議語義的AOP)都可以被作成一個安全的對象。儘管如此,大多數Spring應用程序將簡單地使用當前支持的三種安全對象類型(AOP聯盟方法定位、AspectJ鏈接點和web請求過濾器調用),而且徹底透明。
Spring Security支持最終用戶可能看到的異常消息的本地化。若是您的應用程序是爲說英語的用戶設計的,您不須要作任何事情,由於默認狀況下全部的安全消息都是英語的。若是您須要支持其餘語言環境,您須要知道的一切都包含在本節中。
全部異常消息均可以本地化,包括與身份驗證失敗和訪問被拒絕(受權失敗)相關的消息。針對開發人員或系統部署人員的異常和日誌消息(包括不正確的屬性、違反接口約定、使用不正確的構造函數、啓動時間驗證、調試級日誌記錄)沒有本地化,而是在Spring Security的代碼中用英語硬編碼。
在spring-security-core-xx.jar中,您會找到一個org.springframework.security包,該包又包含一個messages.properties文件,以及一些常見語言的本地化版本。這應該由您的應用程序上下文來引用,由於Spring Security 類實現了Spring的MessageSourceAware 接口,並指望消息解析器在應用程序上下文啓動時被依賴注入。一般,您須要作的只是在應用程序上下文中註冊一個bean來引用消息。下面是一個例子:
messages.properties是根據標準資源包命名的,表明Spring Security消息支持的默認語言。這個默認文件是英文的。
若是您但願自定義messages.properties文件,或者支持其餘語言,您應該複製該文件,對其進行相應的重命名,並在上面的bean定義中註冊它。
這個文件中沒有大量的消息鍵,因此本地化不該該被認爲是一個主要的舉措。若是您確實執行了此文件的本地化,請考慮經過記錄JIRA任務並附加適當命名的本地化版本的messages.properties來與社區共享您的工做。
spring安全依賴於Spring的本地化支持,以便實際查找適當的消息。爲了實現這一點,您必須確保來自傳入請求的區域設置存儲在Spring的org . Spring framework . context . i18n . localeContextholder中。Spring MVC的DispatcherServlet會自動爲您的應用程序執行此操做,可是因爲Spring Security的過濾器是在此以前調用的,所以在調用過濾器以前,須要將LocaleContextHolder設置爲包含正確的區域。您能夠本身在一個過濾器中完成這項工做(這個過濾器必須在Spring Security過濾器以前)。有關在Spring中使用本地化的更多詳細信息,請參考Spring框架文檔。「contacts人」示例應用程序被設置爲使用本地化消息。