15.1. `FilterSecurityInterceptor`

15.1. FilterSecurityInterceptor

我們在討論 9.5. 存取控制 (授權管理) 的時候已經有簡單的看過 FilterSecurityInterceptor,而已經在命名空間使用 <intercept-url> 元素對它做設定。現在我們要來看如何仔細的設定它來給 FilterChainProxy 使用,順帶提到它的同伴 ExceptionTranslationFilter

典型的設定範例如下:

<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource">
	<security:filter-security-metadata-source>
	<security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
	<security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
	</security:filter-security-metadata-source>
</property>
</bean>

FilterSecurityInterceptor 負責處理 HTTP 資源的安全,它需要 AuthenticationManagerAccessDecisionManager 的參考,它也提供針對不同 HTTP URL 請求的 configuration attributes,請參考 之前對於 configuration attributes 的討論

有兩種方式可以使用 configuration attributes 來對 FilterSecurityInterceptor 做設定。

第一種就是如上面程式碼所示,使用 <filter-security-metadata-source> 命名空間元素。這跟命名空間設定章節提到的 <http> 很類似,但 <interceptor-url> 子元素只使用 patternaccess 屬性,並用逗點分隔適用於個別 HTTP URL 的不同 configuration attributes。

第二種你必須撰寫你自己的 SecurityMetadataSource,但這已經超出這份文件的範圍。不過不論使用哪種方法,SecurityMetadataSource 都是負責用來回傳一個 List<ConfigAttribute>,這個列表包含所有關聯到一個已受保護的 HTTP URL 的所有 configuration attributes。

值得注意的是 FilterSecurityInterceptor.setSecurityMetadataSource() 方法其實預期接收一個 FilterInvocationSecurityMetadataSource 的實例當入參。FilterInvocationSecurityMetadataSource 是一個標記用介面,是 SecurityMetadataSource 的子介面,它只是用來表示 SecurityMetadataSource 了解 FilterInvocation

為了方便講解,我們後面會用 SecurityMetadataSource 來指稱 FilterInvocationSecurityMetadataSource,因為兩者之間的差異對多數使用者來說都沒有關係。

透過將請求 URL 與設定好的 pattern 屬性比對,由命名空間語法建立的 SecurityMetadataSource 會取得對應特定的 FilterInvocation 的 configuration attributes,這個行為與以命名空間做設定是相同的。預設會將所有表達式當作 Apache Ant 風格路徑,也支援正則表達式以處理更複雜的狀況,request-matcher 屬性就是用來要使用怎樣的樣式。但是將在同一個定義當中,表達式是不能混用的。

如果將前一個範例寫成正則表達式則會如下:

<bean id="filterInvocationInterceptor"
	class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="runAsManager" ref="runAsManager"/>
<property name="securityMetadataSource">
	<security:filter-security-metadata-source request-matcher="regex">
	<security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
	<security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
	</security:filter-security-metadata-source>
</property>
</bean>

比對動作會依照樣式設定的順序來進行,所以越特殊的樣式應該定義在更前面,如上面的範例所示。