9. Technical Overview 技術概述

節日快樂發表於2020-08-16

9.1 Runtime Environment 執行環境

Spring Security 3.0需要Java 5.0執行時環境或更高版本。由於Spring Security的目標是以獨立的方式執行,所以沒有必要將任何特殊的配置檔案放入Java執行時環境中。特別是,不需要配置特殊的Java身份驗證和授權服務(JAAS)策略檔案,也不需要將Spring Security放在公共的類路徑位置。

同樣,如果您使用的是EJB容器或Servlet容器,就不需要在任何地方放置任何特殊的配置檔案,也不需要在伺服器類載入器中包含Spring Security。所有必需的檔案都將包含在您的應用程式中。

這種設計提供了最大的部署時間靈活性,因為您可以簡單地將您的目標工件(無論是JAR、WAR還是EAR)從一個系統複製到另一個系統,它將立即工作。

9.2 Core Components (核心元件)

在Spring Security 3.0中,spring-security-core jar的內容被剝離到最低限度。它不再包含任何與網路應用安全、LDAP或名稱空間配置相關的程式碼。我們將在這裡看一看核心模組中的一些Java型別。它們代表框架的構建塊,所以如果您需要簡單的名稱空間配置,那麼理解它們是什麼很重要,即使您實際上不需要直接與它們互動。

9.2.1 SecurityContextHolder, SecurityContext and Authentication Objects(安全上下文持有者、安全上下文和身份驗證物件)

最基本的物件是SecurityContextHolder(安全上下文持有者)。我們在這裡儲存應用程式當前安全上下文的詳細資訊,包括當前使用該應用程式的主體的詳細資訊。預設情況下,SecurityContextHolder使用ThreadLocal來儲存這些細節,這意味著安全上下文始終對同一執行執行緒中的方法可用,即使安全上下文沒有作為引數顯式傳遞給這些方法。這種情況下使用ThreadLocal是非常安全的,只要記得在處理完當前主體的請求以後,把這個執行緒清除就行了。當然,Spring Security自動幫你管理這一切了, 你就不用擔心什麼了。

有些程式並不適合使用ThreadLocal,因為它們處理執行緒的特殊方法。比如Swing客戶端也許希望Java Virtual Machine裡所有的執行緒 都使用同一個安全環境。SecurityContextHolder可以在啟動時配置策略,以指定您希望如何儲存上下文。對於獨立的應用程式,您可以使用SecurityContextHolderSecurityContextHolder可以在啟動時配置策略,以指定您希望如何儲存上下文。對於獨立的應用程式,您可以使用SecurityContextHolder.MODE_GLOBAL策略。其他程式可能也想由安全執行緒產生的執行緒也承擔同樣的安全標識。這是通過使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL實現。第一個是設定系統屬性,第二個是呼叫SecurityContextHolder的靜態方法。大多數應用程式不需要修改預設值,但是如果你想要修改,可以看一下SecurityContextHolder的JavaDocs中的詳細資訊瞭解更多。

Obtaining information about the current user(獲取關於當前使用者的資訊)

在SecurityContextHolder中,我們儲存當前與應用程式互動的主體的詳細資訊。Spring Security使用一個身份驗證物件來表示這些資訊。您通常不需要自己建立身份驗證物件,但是使用者查詢身份驗證物件是很常見的。您可以從應用程式中的任何位置使用以下程式碼塊來獲取當前經過身份驗證的使用者的名稱,例如:

 

9. Technical Overview  技術概述
 

呼叫getContext()返回的物件是SecurityContext介面的一個例項。這是儲存線上程本地儲存中的物件。正如我們將在下面看到的,Spring Security中的大多數身份驗證機制都返回一個UserDetails例項作為主體。

9.2.2 The UserDetailsService(使用者詳細資訊服務)

從上面的程式碼片段中需要注意的另一點是,您可以從身份驗證物件中獲取一個主體。主體只是一個客體。大多數情況下,這可以轉換成一個UserDetails物件。UserDetails是Spring安全的核心介面。它代表一個主體,但是以一種可擴充套件的和特定於應用程式的方式。將UserDetails視為您自己的使用者資料庫和SecurityContextHolder內部的Spring Security需要之間的介面卡。作為來自您自己的使用者資料庫的表示,您經常會將UserDetails轉換為您的應用程式提供的原始物件,因此您可以呼叫特定於業務的方法(如getEmail(),getEmployeeNumber(),等等)。

現在你可能想知道,我什麼時候提供一個使用者詳細資訊物件?我怎麼做呢?我想你說這個東西是宣告式的,我不需要寫任何程式碼——什麼給出了?

簡而言之,有一個叫做UserDetailsService(使用者詳細服務)的特殊介面。此介面上的唯一方法接受基於字串的使用者名稱引數並返回UserDetails(使用者詳細資訊):

 

9. Technical Overview  技術概述
 

這是在Spring Security中為使用者載入資訊的最常見的方法,當需要關於使用者的資訊時,您會在整個框架中看到它的使用。

在成功的身份驗證中,UserDetails(使用者詳細資訊)用於構建儲存在SecurityContextHolder中的Authentication(身份驗證物件)(下面將詳細介紹)。好訊息是我們提供了大量的使用者細節服務實現,包括一個使用記憶體對映(InMemoryDaoImpl)的實現和一個使用JDBC (JdbcDaoImpl)的實現。然而,大多數使用者傾向於編寫自己的程式碼,他們的實現通常只是簡單地位於代表他們的僱員、客戶或應用程式的其他使用者的現有資料訪問物件(DAO)之上。請記住,無論您的UserDetailsService返回什麼,都可以使用上面的程式碼片段從安全上下文持有者獲得。

關於UserDetailsService經常會有一些混淆。它純粹是使用者資料的DAO,除了向框架內的其他元件提供資料之外,不執行其他功能。特別是,它不會對使用者進行身份驗證,這是由AuthenticationManager完成的。在許多情況下,如果需要自定義身份驗證過程,直接實現AuthenticationProvider更有意義。

9.2.3 GrantedAuthority (授予授權)

除了主體,身份驗證提供的另一個重要方法是getAuthorities()。這個方法提供了一個授權物件的陣列。毫不奇怪,授權是授予委託人的權力。這種許可權通常是“角色”,例如ROLE_ADMINISTRATOR或ROLE _ HR _ SUPERVISOR。這些角色稍後將針對web授權、方法授權和域物件授權進行配置。Spring Security的其他部分能夠解釋這些許可權,並期望它們存在。授權物件通常由UserDetailsService載入。

通常授予的許可權物件是應用程式範圍的許可權。它們並不特定於給定的域物件。因此,您不太可能擁有授權來表示對僱員物件編號54的許可權,因為如果有成千上萬個這樣的許可權,您將很快耗盡記憶體(或者至少導致應用程式花很長時間來驗證使用者)。當然,Spring Security是專門為處理這種常見需求而設計的,但是您可以使用專案的域物件安全功能來實現這一目的。

9.2.4 Summary  摘要

簡單回顧一下,目前為止我們看到的Spring Security的主要構建模組是:

SecurityContextHolder,提供對SecurityContext的訪問。

SecurityContext,用於儲存Authentication和可能的特定於請求的安全資訊。

Authentication,以Spring安全特定的方式代表主體。

GrantedAuthority,以反映授予主體的應用程式範圍的許可權。

UserDetails,提供必要的資訊,以便從應用程式的DAOs或其他安全資料來源構建身份驗證物件。

UserDetailsService,當傳入基於字串的使用者名稱(或證照標識等)時建立UserDetails。

現在您已經瞭解了這些重複使用的元件,讓我們更仔細地看看身份驗證的過程。

9.3 Authentication (許可權認證)

Spring Security可以參與許多不同的身份驗證環境。雖然我們建議人們使用Spring Security進行身份驗證,而不要與現有的容器管理身份驗證整合,但是它仍然受到支援,就像與您自己的專有身份驗證系統整合一樣。

9.3.1什麼是spring安全認證?

讓我們考慮一個大家都熟悉的標準身份驗證場景。

1、提示使用者輸入使用者名稱和密碼進行登入。

2、系統(成功)驗證使用者名稱的密碼是否正確。

3、獲取該使用者的上下文資訊(他們的角色列表等等)。

4、為使用者建立安全上下文。

5、使用者繼續執行一些操作,這些操作可能受到訪問控制機制的保護,該機制根據當前的安全上下文資訊檢查操作所需的許可權。

前三項構成了身份驗證過程,因此我們將看看這些是如何在Spring Security中發生的。

1、使用者名稱和密碼被獲取並組合到一個UsernamePasswordAuthenticationToken的例項中(這是我們前面看到的身份驗證介面的一個例項)。

2、令牌被傳遞給AuthenticationManager的一個例項進行驗證。

3、AuthenticationManager在身份驗證成功時返回完全填充的Authentication。

4、通過呼叫securitycontextholder . GetContext()來建立安全上下文。設定身份驗證(…),傳入返回的身份驗證物件。

從這一點上來看,使用者被認為是被驗證的。讓我們看看一些程式碼作為一個例子:

 

9. Technical Overview  技術概述
 

 

9. Technical Overview  技術概述
 

這裡,我們編寫了一個小程式,要求使用者輸入使用者名稱和密碼,並執行上面的序列。我們在這裡實現的身份驗證管理器將驗證使用者名稱和密碼相同的任何使用者。它為每個使用者分配一個角色。上面的輸出將類似於:

 

9. Technical Overview  技術概述
 

請注意,你通常不需要寫任何這樣的程式碼。這個過程通常會發生在內部,以一個web認證過濾器為例,我們剛剛在這裡的程式碼顯示,在Spring Security中究竟是什麼構成了驗證的問題,有一個相對簡單的答案。使用者驗證時,SecurityContextHolder包含一個完全填充的Authentication物件的使用者進行身份驗證。

預設情況下,使用StrictHttpFirewall。該實現拒絕看似惡意的請求。如果它對你的需求來說太嚴格,那麼你可以定製什麼型別的請求被拒絕。然而,重要的是你要知道這可能會使你的應用程式受到攻擊。例如,如果您希望利用Spring MVC的矩陣變數,可以在XML中使用以下配置:

 

9. Technical Overview  技術概述
 

同樣的事情也可以通過Java配置來實現,方法是公開一個StrictHttpFirewall bean。

 

9. Technical Overview  技術概述
 

9.3.2 Setting the SecurityContextHolder Contents Directly(直接設定安全上下文持有者內容)

事實上,Spring Security並不介意如何將身份驗證物件(Authentication)放入SecurityContextHolder中。唯一關鍵的要求是SecurityContextHolder包含一個身份驗證(Authentication),該身份驗證在抽象安全介面(AbstractSecurityInterceptor)(我們將在後面詳細討論)需要授權使用者操作之前代表一個主體。

您可以(許多使用者也可以)編寫自己的過濾器或MVC控制器,以提供與不基於Spring安全的身份驗證系統的互操作性。例如,您可能正在使用容器管理的身份驗證,這使得當前使用者可以從執行緒本地或JNDI位置訪問。或者,你可能在一家擁有傳統專有認證系統的公司工作,這是一個你幾乎無法控制的公司“標準”。在這種情況下,很容易讓Spring Security工作,並且仍然提供授權功能。您需要做的只是編寫一個過濾器(或等效工具),從一個位置讀取第三方使用者資訊,構建一個Spring安全特定的身份驗證物件(Authentication),並將其放入安全上下文持有者(SecurityContextHolder)。在這種情況下,您還需要考慮通常由內建身份驗證基礎結構自動處理的事情。例如,在向客戶端腳註寫入響應之前,您可能需要先建立一個HTTP會話來快取請求之間的上下文:一旦提交了響應,就不可能建立會話。

如果您想知道AuthenticationManager是如何在實際示例中實現的,我們將在核心服務一章( core services chapter)中討論這一點。

9.4 Authentication in a Web Application (web應用中的認證)

現在讓我們探討一下在web應用程式中使用Spring Security的情況(沒有啟用web.xml安全性)。如何對使用者進行身份驗證並建立安全上下文?

考慮一個典型的web應用程式的身份驗證過程:

1、你訪問主頁,點選一個連結。

2、一個請求到達伺服器,伺服器決定您已經請求了一個受保護的資源。

3、由於您目前沒有通過身份驗證,伺服器會發回一個響應,指示您必須通過身份驗證。該響應或者是一個HTTP響應程式碼,或者是一個到特定網頁的重定向。

4、根據身份驗證機制,您的瀏覽器要麼重定向到特定的網頁以便您填寫表單,要麼瀏覽器以某種方式檢索您的身份(通過基本身份驗證對話方塊、cookie、X.509證照等)。)。

5、瀏覽器將向伺服器發回響應。這要麼是一個包含您填寫的表單內容的HTTP POST,要麼是一個包含您的身份驗證詳細資訊的HTTP標頭。

6、接下來,伺服器將決定呈現的憑證是否有效。如果它們是有效的,下一步就會發生。如果無效,通常你的瀏覽器會被要求再試一次(所以你回到上面的第二步)。

7、將重試您為導致身份驗證過程而提出的原始請求。希望你已經通過了足夠的授權來訪問受保護的資源。如果您有足夠的訪問許可權,請求將會成功。否則,您將收到一個返回的HTTP錯誤程式碼403,這意味著“禁止”。

Spring Security有不同的類來負責上面描述的大部分步驟。主要參與者(按使用順序)是異常轉換過濾器(ExceptionTranslationFilter),一個AuthenticationEntryPoint和一個“身份驗證機制(authentication mechanism)”,負責呼叫我們在上一節中看到的AuthenticationManager。

9.4.1 ExceptionTranslationFilter (異常轉換過濾器)

ExceptionTranslationFilter是一個Spring安全篩選器,負責檢測引發的任何Spring安全異常。這種異常通常會被抽象安全介面(AbstractSecurityInterceptor)丟擲,它是授權服務的主要提供者。我們將在下一節討論抽象安全介面,但是現在我們只需要知道它產生了Java異常,並且對HTTP或者如何驗證主體一無所知。相反,ExceptionTranslationFilter提供此服務,具體負責返回錯誤程式碼403(如果主體已經過身份驗證,因此缺少足夠的訪問許可權,如上面的步驟七),或者啟動AuthenticationEntryPoint(如果主體尚未通過身份驗證,因此我們需要開始步驟三)。

9.4.2 AuthenticationEntryPoint (認證入口點)

AuthenticationEntryPoint負責上述列表中的第三步。可以想象,每個web應用程式都有一個預設的身份驗證策略(可以像Spring Security中的其他任何東西一樣進行配置,但是現在讓我們保持簡單)。每個主要的身份驗證系統都有自己的AuthenticationEntryPoint實現,它通常執行步驟3中描述的操作之一。

9.4.3 Authentication Mechanism(認證機制)

一旦您的瀏覽器提交了您的身份驗證憑據(或者作為一個HTTP表單帖子,或者作為一個HTTP頭),伺服器上就需要有一些東西來“收集”這些身份驗證的詳細資訊。到現在為止,我們已經在上面列表的第六步了。在Spring Security中,我們為從使用者代理(通常是web瀏覽器)收集身份驗證詳細資訊的功能起了一個特殊的名字,將其稱為“身份驗證機制(authentication mechanism)”。例如基於表單的登入和基本身份驗證。一旦從使用者代理收集了身份驗證詳細資訊,就會構建一個身份驗證(Authentication)“請求”物件,然後呈現給身份驗證管理器(AuthenticationManager)。

在身份驗證機制收到完全填充的身份驗證(Authentication)物件後,它將認為請求有效,將身份驗證(Authentication)放入SecurityContextHolder中,並重試原始請求(上面的第七步)。另一方面,如果AuthenticationManager拒絕了請求,身份驗證機制將要求使用者代理重試(上面的第二步)。

9.4.4 Storing the SecurityContext between requests(在請求之間儲存安全性上下文)

根據應用程式的型別,可能需要一個策略來儲存使用者操作之間的安全上下文。在典型的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()總是返回一個新的上下文例項。

9.5 Access-Control (Authorization) in Spring Security(Spring安全中的訪問控制(授權))

在Spring Security中,負責做出訪問控制決策的主要介面是訪問決策管理器(AccessDecisionManager)。它有一個decide方法,它需要一個Authentication物件請求訪問、一個"secure object"(安全物件)(見下文)和安全後設資料屬性的列表適用的物件(例如授予訪問所需的角色列表)。

9.5.1 Security and AOP Advice(安全和AOP建議)

如果你熟悉AOP,你會意識到有不同型別的建議可用:之前,之後,丟擲和周圍。迴圈建議非常有用,因為advisorSpring Security為方法呼叫和web請求提供了一個全面的建議。我們使用Spring的標準AOP支援實現了方法呼叫的迴圈建議,並使用標準過濾器實現了web請求的迴圈建議。可以選擇是否繼續方法呼叫、是否修改響應以及是否丟擲異常。

對於那些不熟悉AOP的人來說,需要理解的關鍵一點是,Spring安全性可以幫助您保護方法呼叫和web請求。多數人對保護他們服務層上的方法呼叫感興趣。這是因為服務層是當前一代Java EE應用程式中大多數業務邏輯所在的地方。如果您只需要保護服務層中的方法呼叫,Spring的標準AOP就足夠了。如果您需要直接保護域物件,您可能會發現AspectJ是值得考慮的。

您可以選擇使用AspectJ或Spring AOP來執行方法授權,也可以選擇使用過濾器來執行web請求授權。你可以同時使用零、一、二或三種方法。主流的使用模式是執行一些web請求授權,再加上服務層上的一些Spring AOP方法呼叫授權。

9.5.2 Secure Objects and the AbstractSecurityInterceptor(安全物件和AbstractSecurityInterceptor)

那麼什麼是“安全物件”?Spring Security使用該術語來指代任何可以應用安全性(例如授權決策)的物件。最常見的例子是方法呼叫和web請求。

每個受支援的安全物件型別都有自己的攔截器類,它是抽象安全攔截器(AbstractSecurityInterceptor)的子類。重要的是,在呼叫抽象安全攔截器(AbstractSecurityInterceptor)時,如果主體已經過身份驗證,安全上下文持有者(SecurityContextHolder)將包含有效的身份驗證(Authentication)。

抽象安全攔截器(AbstractSecurityInterceptor)為處理安全物件請求提供了一致的工作流,通常:

1、查詢與當前請求相關聯的“配置屬性”。

2、將安全物件、當前身份驗證和配置屬性提交給訪問決策管理器(AccessDecisionManager)進行授權決策。

3、有可能在呼叫的過程中,對Authentication進行修改。

4、允許安全物件呼叫繼續進行(假設授予了訪問許可權)。

5、呼叫返回後,呼叫AfterInvocationManager(如果已配置)。如果呼叫引發了異常,將不會呼叫AfterInvocationManager。

What are Configuration Attributes?(什麼是配置屬性?)

一個"配置屬性"可以看做是一個字串,它對於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。

Run As Manager(執行管理器)

假設AccessDecisionManager決定允許執行這個請求,AbstractSecurityInterceptor會正常執行這個請求。話雖如此,在極少數情況下,使用者可能希望用不同的身份驗證來替換安全上下文(SecurityContext)中的身份驗證(Authentication),該身份驗證由呼叫執行管理器(RunAsManager)的訪問決策管理器(AccessDecisionManager)來處理。

在相當不常見的情況下,例如服務層方法需要呼叫遠端系統並顯示不同的標識時,這可能很有用。 由於Spring Security會自動將安全身份從一臺伺服器傳播到另一臺伺服器(假設您使用的是正確配置的RMI或HttpInvoker遠端協議客戶端),因此這很有用。

After Invocation Manager (呼叫後管理器)

在安全物件呼叫繼續進行之後,然後返回-這可能意味著方法呼叫完成或過濾器鏈繼續進行-AbstractSecurityInterceptor獲得了處理呼叫的最後機會。在此階段,AbstractSecurityInterceptor對可能修改返回物件感興趣。 我們可能希望發生這種情況,因為無法在安全物件呼叫的“途中”做出授權決定。由於高度可插拔,AbstractSecurityInterceptor會將控制權傳遞給AfterInvocationManager,以根據需要實際修改物件。 此類甚至可以完全替換物件,或者引發異常,也可以按照其選擇的任何方式對其進行更改。呼叫後檢查僅在呼叫成功的情況下執行。 如果發生異常,將跳過其他檢查。圖9.1“安全攔截器和“安全物件”模型”中顯示了AbstractSecurityInterceptor及其相關物件。

 

9. Technical Overview  技術概述
 


Extending the Secure Object Model(擴充套件安全物件模型)

只有考慮一種全新的攔截和授權請求方式的開發人員才需要直接使用安全物件。例如,可以構建一個新的安全物件來保護對訊息傳遞系統的呼叫。任何需要安全性並且提供攔截呼叫方式的東西(比如關於建議語義的AOP)都能夠被做成一個安全的物件。儘管如此,大多數Spring應用程式將簡單地使用當前支援的三種安全物件型別(AOP聯盟方法定位、AspectJ連線點和web請求過濾器呼叫),並且完全透明。

9.5.2 Secure Objects and the AbstractSecurityInterceptor(安全物件和AbstractSecurityInterceptor)

那麼什麼是“安全物件”?Spring Security使用該術語來指代任何可以應用安全性(例如授權決策)的物件。最常見的例子是方法呼叫和web請求。

每個受支援的安全物件型別都有自己的攔截器類,它是抽象安全攔截器(AbstractSecurityInterceptor)的子類。重要的是,在呼叫抽象安全攔截器(AbstractSecurityInterceptor)時,如果主體已經過身份驗證,安全上下文持有者(SecurityContextHolder)將包含有效的身份驗證(Authentication)。

抽象安全攔截器(AbstractSecurityInterceptor)為處理安全物件請求提供了一致的工作流,通常:

1、查詢與當前請求相關聯的“配置屬性”。

2、將安全物件、當前身份驗證和配置屬性提交給訪問決策管理器(AccessDecisionManager)進行授權決策。

3、有可能在呼叫的過程中,對Authentication進行修改。

4、允許安全物件呼叫繼續進行(假設授予了訪問許可權)。

5、呼叫返回後,呼叫AfterInvocationManager(如果已配置)。如果呼叫引發了異常,將不會呼叫AfterInvocationManager。

What are Configuration Attributes?(什麼是配置屬性?)

一個"配置屬性"可以看做是一個字串,它對於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。

Run As Manager(執行管理器)

假設AccessDecisionManager決定允許執行這個請求,AbstractSecurityInterceptor會正常執行這個請求。話雖如此,在極少數情況下,使用者可能希望用不同的身份驗證來替換安全上下文(SecurityContext)中的身份驗證(Authentication),該身份驗證由呼叫執行管理器(RunAsManager)的訪問決策管理器(AccessDecisionManager)來處理。

在相當不常見的情況下,例如服務層方法需要呼叫遠端系統並顯示不同的標識時,這可能很有用。 由於Spring Security會自動將安全身份從一臺伺服器傳播到另一臺伺服器(假設您使用的是正確配置的RMI或HttpInvoker遠端協議客戶端),因此這很有用。

After Invocation Manager (呼叫後管理器)

在安全物件呼叫繼續進行之後,然後返回-這可能意味著方法呼叫完成或過濾器鏈繼續進行-AbstractSecurityInterceptor獲得了處理呼叫的最後機會。在此階段,AbstractSecurityInterceptor對可能修改返回物件感興趣。 我們可能希望發生這種情況,因為無法在安全物件呼叫的“途中”做出授權決定。由於高度可插拔,AbstractSecurityInterceptor會將控制權傳遞給AfterInvocationManager,以根據需要實際修改物件。 此類甚至可以完全替換物件,或者引發異常,也可以按照其選擇的任何方式對其進行更改。呼叫後檢查僅在呼叫成功的情況下執行。 如果發生異常,將跳過其他檢查。圖9.1“安全攔截器和“安全物件”模型”中顯示了AbstractSecurityInterceptor及其相關物件。

 

9. Technical Overview  技術概述
 


Extending the Secure Object Model(擴充套件安全物件模型)

只有考慮一種全新的攔截和授權請求方式的開發人員才需要直接使用安全物件。例如,可以構建一個新的安全物件來保護對訊息傳遞系統的呼叫。任何需要安全性並且提供攔截呼叫方式的東西(比如關於建議語義的AOP)都能夠被做成一個安全的物件。儘管如此,大多數Spring應用程式將簡單地使用當前支援的三種安全物件型別(AOP聯盟方法定位、AspectJ連線點和web請求過濾器呼叫),並且完全透明。

9.6 Localization 本地化

Spring Security支援終端使用者可能看到的異常訊息的本地化。如果您的應用程式是為說英語的使用者設計的,您不需要做任何事情,因為預設情況下所有的安全訊息都是英語的。如果您需要支援其他語言環境,您需要知道的一切都包含在本節中。

所有異常訊息都可以本地化,包括與身份驗證失敗和訪問被拒絕(授權失敗)相關的訊息。針對開發人員或系統部署人員的異常和日誌訊息(包括不正確的屬性、違反介面約定、使用不正確的建構函式、啟動時間驗證、除錯級日誌記錄)沒有本地化,而是在Spring Security的程式碼中用英語硬編碼。

在spring-security-core-xx.jar中,您會找到一個org.springframework.security包,該包又包含一個messages.properties檔案,以及一些常見語言的本地化版本。這應該由您的應用程式上下文來引用,因為Spring Security 類實現了Spring的MessageSourceAware 介面,並期望訊息解析器在應用程式上下文啟動時被依賴注入。通常,您需要做的只是在應用程式上下文中註冊一個bean來引用訊息。下面是一個例子:

 

9. Technical Overview  技術概述
 

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人”示例應用程式被設定為使用本地化訊息。

 

相關文章