預先驗證情境

範例包括 X.509、Siteminder,以及應用程式執行所在的 Java EE 容器進行驗證。當使用預先驗證時,Spring Security 必須

  • 識別發出請求的使用者。

  • 取得使用者的授權。

詳細資訊取決於外部驗證機制。在 X.509 的情況下,使用者可能會透過其憑證資訊來識別,或者在 Siteminder 的情況下,透過 HTTP 請求標頭來識別。如果依賴容器驗證,則透過呼叫傳入 HTTP 請求的 getUserPrincipal() 方法來識別使用者。在某些情況下,外部機制可能會為使用者提供角色和授權資訊。但是,在其他情況下,您必須從單獨的來源取得授權,例如 UserDetailsService

預先驗證架構類別

由於大多數預先驗證機制都遵循相同的模式,因此 Spring Security 擁有一組類別,這些類別提供了一個內部框架,用於實作預先驗證的驗證提供者。這消除了重複,並允許以結構化的方式新增新的實作,而無需從頭開始編寫所有內容。如果您想使用 X.509 驗證 之類的功能,則無需了解這些類別,因為它已經有一個命名空間組態選項,使用起來更簡單且更容易上手。如果您需要使用明確的 Bean 組態,或者計劃編寫自己的實作,則需要了解所提供的實作如何運作。您可以在 org.springframework.security.web.authentication.preauth 下找到這些類別。我們在這裡僅提供一個概述,因此您應該查閱 Javadoc 和原始碼以取得適當的資訊。

AbstractPreAuthenticatedProcessingFilter

此類別檢查安全性內容的目前內容,如果內容為空,則嘗試從 HTTP 請求中提取使用者資訊,並將其提交給 AuthenticationManager。子類別會覆寫以下方法以取得此資訊。

覆寫 AbstractPreAuthenticatedProcessingFilter
  • Java

  • Kotlin

protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);

protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
protected abstract fun getPreAuthenticatedPrincipal(request: HttpServletRequest): Any?

protected abstract fun getPreAuthenticatedCredentials(request: HttpServletRequest): Any?

在呼叫這些方法之後,篩選器會建立一個 PreAuthenticatedAuthenticationToken,其中包含傳回的資料,並提交以進行驗證。此處的「驗證」實際上只是指進一步的處理,以便可能載入使用者的授權,但遵循標準的 Spring Security 驗證架構。

如同其他 Spring Security 驗證篩選器,預先驗證篩選器具有 authenticationDetailsSource 屬性,預設情況下,該屬性會建立 WebAuthenticationDetails 物件,以將其他資訊儲存在 Authentication 物件的 details 屬性中,例如工作階段識別碼和來源 IP 位址。如果可以從預先驗證機制取得使用者角色資訊,則資料也會儲存在此屬性中,詳細資訊會實作 GrantedAuthoritiesContainer 介面。這使驗證提供者能夠讀取外部分配給使用者的授權。接下來,我們來看一個具體的範例。

J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource

如果篩選器配置了 authenticationDetailsSource,它是此類別的實例,則透過針對預先決定的「可對應角色」集合中的每個角色呼叫 isUserInRole(String role) 方法來取得授權資訊。該類別從配置的 MappableAttributesRetriever 取得這些角色。可能的實作包括在應用程式內容中硬式編碼列表,以及從 web.xml 檔案中的 <security-role> 資訊中讀取角色資訊。預先驗證範例應用程式使用後一種方法。

還有一個額外階段,角色(或屬性)透過使用配置的 Attributes2GrantedAuthoritiesMapper 對應到 Spring Security GrantedAuthority 物件。預設值只是將常用的 ROLE_ 前綴新增到名稱中,但它讓您可以完全控制行為。

PreAuthenticatedAuthenticationProvider

預先驗證的提供者只需載入使用者的 UserDetails 物件。它透過委派給 AuthenticationUserDetailsService 來完成此操作。後者類似於標準的 UserDetailsService,但採用 Authentication 物件,而不僅僅是使用者名稱

public interface AuthenticationUserDetailsService {
	UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
}

此介面也可能還有其他用途,但是,對於預先驗證,它允許存取封裝在 Authentication 物件中的授權,正如我們在前一節中看到的那樣。PreAuthenticatedGrantedAuthoritiesUserDetailsService 類別執行此操作。或者,它可以透過 UserDetailsByNameServiceWrapper 實作委派給標準的 UserDetailsService

Http403ForbiddenEntryPoint

AuthenticationEntryPoint 負責啟動未驗證使用者的驗證程序(當他們嘗試存取受保護的資源時)。但是,在預先驗證的情況下,這不適用。如果您不將預先驗證與其他驗證機制結合使用,則只會使用此類別的實例來配置 ExceptionTranslationFilter。如果使用者被 AbstractPreAuthenticatedProcessingFilter 拒絕,導致空驗證,則會呼叫它。如果呼叫它,它始終會傳回 403-forbidden 回應碼。

具體實作

X.509 驗證在其 自己的章節 中介紹。在這裡,我們來看一些類別,這些類別為其他預先驗證情境提供支援。

請求標頭驗證 (Siteminder)

外部驗證系統可以透過在 HTTP 請求上設定特定標頭,向應用程式提供資訊。Siteminder 就是一個眾所周知的範例,它在名為 SM_USER 的標頭中傳遞使用者名稱。RequestHeaderAuthenticationFilter 類別支援此機制,該類別僅從標頭中提取使用者名稱。預設情況下,它使用名稱 SM_USER 作為標頭名稱。請參閱 Javadoc 以取得更多詳細資訊。

當使用像這樣的系統時,框架根本不執行任何驗證檢查,而且極其重要的是,外部系統已正確配置並保護對應用程式的所有存取。如果攻擊者能夠偽造其原始請求中的標頭而未被偵測到,則他們可能會選擇他們想要的任何使用者名稱。

Siteminder 範例組態

以下範例顯示了使用此篩選器的典型組態

<security:http>
<!-- Additional http configuration omitted -->
<security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
</security:http>

<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>

<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
	<bean id="userDetailsServiceWrapper"
		class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
	<property name="userDetailsService" ref="userDetailsService"/>
	</bean>
</property>
</bean>

<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>

我們在這裡假設 安全性命名空間 用於組態。也假設您已將 UserDetailsService(稱為 "userDetailsService")新增到您的組態中,以載入使用者的角色。

Java EE 容器驗證

J2eePreAuthenticatedProcessingFilter 類別從 HttpServletRequestuserPrincipal 屬性中提取使用者名稱。此篩選器的使用通常會與 Java EE 角色的使用結合,如先前在 J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 中所述。

在程式碼庫中,有一個 範例應用程式 使用了此方法,因此如果您有興趣,請從 Github 取得程式碼並查看應用程式內容檔案。