10.2 核心Security過濾器

在使用Spring Security的Web應(yīng)用程序中浊伙,總會用到一些關(guān)鍵的過濾器摊阀,所以我們首先來看看這些過濾器及其支持類和接口蔬崩。我們不會涵蓋每一個特性涮瞻,因此如果您想獲得完整的圖片绣版,一定要查看JavaDoc中的特性胶台。

10.2.1?FilterSecurityInterceptor

在討論?access-control in general時,我們已經(jīng)簡要地看過了 FilterSecurityInterceptor?杂抽,并且我們已經(jīng)將它與命名空間的<intercept url>元素組合在一起以進(jìn)行內(nèi)部配置一起使用≌┗#現(xiàn)在,我們將看到如何用 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?負(fù)責(zé)處理HTTP資源的安全性。它需要對 AuthenticationManager?AccessDecisionManager的引用。它還提供了適用于不同HTTP URL請求的配置屬性阅仔。請參閱技術(shù)介紹?the original discussion on these?吹散。

FilterSecurityInterceptor?可以通過兩種方式攜帶屬性參數(shù)進(jìn)行配置。第一個是使用<filter-security-metadata-source>namespace元素八酒,如上圖所示空民。這類似于命名空間章節(jié)中的<http>元素,但<intercept url>子元素僅使用pattern?access?屬性羞迷。逗號用于分隔應(yīng)用于每個HTTP URL的不同配置屬性界轩。第二種選擇是編寫自己的SecurityMetadataSource,但這超出了本文檔的范圍衔瓮。無論使用何種方法耸棒,SecurityMetadataSource?都負(fù)責(zé)返回一個包含與單個安全HTTP URL關(guān)聯(lián)的所有配置屬性的 List<ConfigAttribute>。

應(yīng)該注意报辱,FilterSecurityInterceptor.setSecurityMetadataSource()?方法實際需要FilterInvocationSecurityMetadataSource?的實例。這是SecurityMetadataSource類的一個子類单山。它只是表示SecurityMetadataSource?理解 FilterInvocations 碍现。為了簡單起見,我們將繼續(xù)將FilterInvocationSecurityMetadataSource?稱為SecurityMetadataSource米奸,因為這種區(qū)別與大多數(shù)用戶幾乎沒有關(guān)聯(lián)昼接。

由命名空間語法創(chuàng)建的 SecurityMetadataSource?通過將請求URL與已配置的 pattern?屬性進(jìn)行匹配來獲取特定?FilterInvocation?的配置屬性。這與命名空間配置的行為方式相同悴晰。默認(rèn)情況下慢睡,將所有表達(dá)式視為Apache Ant路徑,并用正則表達(dá)式來支持更復(fù)雜的情況铡溪。request-matcher?屬性用于指定正在使用的模式類型漂辐。不能在同一定義中混合表達(dá)式語法。例如棕硫,以前使用正則表達(dá)式而不是Ant路徑的配置將編寫如下:

<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>

Patterns?總是按照其定義的順序進(jìn)行評估髓涯。因此,在列表中定義更具體的模式比定義不那么具體的模式要更靠前哈扮。這反映在上面的示例中纬纪,其中更具體的 /secure/super/ pattern比不那么具體的 /secure/ pattern?靠前。如果它們被顛倒滑肉,/secure/ pattern將始終匹配包各,而 /secure/super/ pattern將永遠(yuǎn)不會被評估。

10.2.2 異常處理過濾器 ExceptionTranslationFilter

ExceptionTranslationFilter??位于安全篩選器堆棧中 FilterSecurityInterceptor?的上方靶庙。它本身不執(zhí)行任何實際的安全強(qiáng)制问畅,但處理安全攔截器拋出的異常,并提供適當(dāng)?shù)腍TTP響應(yīng)。

<bean id="exceptionTranslationFilter"

????????class="org.springframework.security.web.access.ExceptionTranslationFilter">

????????<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>

????????<property name="accessDeniedHandler" ref="accessDeniedHandler"/>

</bean>

<bean id="authenticationEntryPoint"

????????class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">

????????<property name="loginFormUrl" value="/login.jsp"/>

</bean>

<bean id="accessDeniedHandler"

? ? ? ?class="org.springframework.security.web.access.AccessDeniedHandlerImpl">

????????<property name="errorPage" value="/accessDenied.htm"/>

</bean>

身份驗證入口點?AuthenticationEntryPoint

如果用戶請求受保護(hù)的HTTP資源按声,但未對其進(jìn)行身份驗證膳犹,則將調(diào)用 AuthenticationEntryPoint?。安全攔截器將沿著調(diào)用堆棧進(jìn)一步拋出適當(dāng)?shù)?AuthenticationException?AccessDeniedException?签则,從而在入口點觸發(fā) commence?方法须床。這樣做的目的是向用戶提供適當(dāng)?shù)捻憫?yīng),以便可以開始身份驗證渐裂。我們在這里使用的是LoginLauthenAuthenticationEntryPoint豺旬,它將請求重定向到不同的URL(通常是登錄頁面)。實際使用的AuthenticationEntryPoint?實現(xiàn)類取決于您希望在應(yīng)用程序中使用的身份驗證機(jī)制柒凉。

訪問拒絕控制器 AccessDeniedHandler

如果用戶已經(jīng)過身份驗證通過族阅,并且試圖訪問受保護(hù)的資源,會發(fā)生什么情況呢膝捞?在正常使用中坦刀,不應(yīng)該發(fā)生這種情況,因為應(yīng)用程序工作流應(yīng)限制為用戶可以訪問的操作蔬咬。例如鲤遥,指向管理頁面的HTML鏈接可能對沒有管理角色的用戶隱藏。但是林艘,您不能依靠隱藏鏈接來實現(xiàn)安全性盖奈,因為用戶總是有可能直接輸入URL來繞過這些限制『或者他們可以修改一個RESTful URL來更改一些參數(shù)值钢坦。您的應(yīng)用程序必須針對這些場景進(jìn)行保護(hù),否則它肯定是不安全的啥酱。通常爹凹,您將使用簡單的Web層安全性來對基本URL應(yīng)用約束,并在服務(wù)層接口上使用更具體的基于方法的安全性來真正確定允許的內(nèi)容镶殷。

如果拋出了 AccessDeniedException?逛万,并且用戶已經(jīng)通過了身份驗證,那么這意味著這個用戶嘗試了一個沒有足夠權(quán)限的操作批钠。在這種情況下宇植,ExceptionTranslationFilter?將調(diào)用第二個策略,即?AccessDeniedHandler埋心。默認(rèn)情況下指郁,使用 AccessDeniedHandlerImpl?,它只向客戶機(jī)發(fā)送403(禁止)響應(yīng)拷呆∠锌玻或者疫粥,您可以顯式配置一個實例(如上面的示例所示),并設(shè)置一個可以被請求轉(zhuǎn)發(fā)到的錯誤頁URL腰懂。這可以是一個簡單的“拒絕訪問”頁面梗逮,如JSP,也可以是一個更復(fù)雜的處理程序绣溜,如MVC控制器慷彤。當(dāng)然,您可以自己實現(xiàn)接口并使用自己的實現(xiàn)怖喻。

還可以在使用命名空間配置應(yīng)用程序時提供自定義的 AccessDeniedHandler?底哗。有關(guān)詳細(xì)信息,請參閱?the namespace appendix锚沸。

SavedRequests 和 RequestCache接口

ExceptionTranslationFilter?的另一個職責(zé)是在調(diào)用 AuthenticationEntryPoint 之前保存當(dāng)前請求跋选。這允許在用戶進(jìn)行身份驗證后還原請求(請參閱先前的Web身份驗證概述)。一個典型的例子是哗蜈,用戶使用一個表單登錄前标,然后由默認(rèn)的SavedRequestAwareAuthenticationSuccessHandler?(見下文)重定向到原始URL。

RequestCache?封裝了存儲和檢索 HttpServletRequest? 實例所需的功能距潘。默認(rèn)情況下炼列,使用HttpSessionRequestCache?,它將請求存儲在 HttpSession?中绽昼。當(dāng)用戶被重定向到原始URL時,RequestCacheFilter的任務(wù)是從緩存中實際還原保存的請求须蜗。

在正常情況下硅确,您不需要修改任何此功能,但保存的請求處理是一種“盡最大努力”的方法明肮,并且可能存在默認(rèn)配置無法處理的情況菱农。這些接口的使用使得它可以從SpringSecurity3.0開始完全插入。

10.2.3 安全上下文持久性篩選器?SecurityContextPersistenceFilter

我們在技術(shù)概述一章中介紹了這個非常重要的過濾器的用途柿估,因此您可能希望在此時重新閱讀該部分循未。讓我們先看看如何配置它與 FilterChainProxy 一起使用★啵基本配置只需要bean本身的妖。

<bean id="securityContextPersistenceFilter"

class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>

正如我們之前看到的,這個過濾器有兩個主要任務(wù)足陨。它負(fù)責(zé)在HTTP請求之間存儲SecurityContext內(nèi)容嫂粟,并在請求完成時清除 SecurityContextHolder。清除存儲上下文的 ThreadLocal?是非常重要的墨缘,因為線程可能會被替換到servlet容器的線程池中星虹,而特定用戶的安全上下文仍然附加零抬。該線程隨后可能會在后期使用,使用錯誤的憑據(jù)執(zhí)行操作宽涌。

安全上下文存儲庫?SecurityContextRepository

從SpringSecurity3.0開始平夜,加載和存儲安全上下文的工作現(xiàn)在被委托給一個單獨的策略接口:

public interface SecurityContextRepository {

SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);

void saveContext(SecurityContext context, HttpServletRequest request,

? ? ? ? HttpServletResponse response);

}

HttpRequestResponseHolder?只是接收請求和響應(yīng)對象的容器,允許用包裝類的實現(xiàn)來替換這些對象卸亮。返回的內(nèi)容將傳遞到過濾器鏈忽妒。

默認(rèn)實現(xiàn)是 HttpSessionSecurityContextRepository,它將安全上下文存儲為 HttpSession?屬性嫡良。此實現(xiàn)最重要的配置參數(shù)是 allowSessionCreation?屬性锰扶,該屬性默認(rèn)為 true,從而允許類在需要會話時為經(jīng)過身份驗證的用戶存儲安全上下文時創(chuàng)建 session(除非進(jìn)行了身份驗證寝受,并且安全上下文的內(nèi)容發(fā)生了改變坷牛,否則不會創(chuàng)建)。如果不希望創(chuàng)建session?很澄,則可以將此屬性設(shè)置為 false:

<bean id="securityContextPersistenceFilter"?

? ? class="org.springframework.security.web.context.SecurityContextPersistenceFilter">

<property name='securityContextRepository'>

? ? <bean class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>

? ? <property name='allowSessionCreation' value='false' />

? ? </bean>

</property>

</bean>

或者京闰,你可以提供一個 NullSecurityContextRepository 實例,一個空對象實現(xiàn)甩苛,它將阻止存儲安全上下文蹂楣,即使在請求期間已經(jīng)創(chuàng)建了會話。

10.2.4?UsernamePasswordAuthenticationFilter

我們現(xiàn)在看到了三個主要的過濾器讯蒲,它們總是出現(xiàn)在Spring Security Web配置中痊土。這三個元素也是由namespace <http>?元素自動創(chuàng)建的,不能用替代項替換∧郑現(xiàn)在唯一缺少的是一個實際的身份驗證機(jī)制赁酝,它允許用戶進(jìn)行身份驗證。此篩選器是最常用的身份驗證篩選器旭等,也是最常用的自定義篩選器酌呆。它還提供由命名空間中的<form login>元素使用的實現(xiàn)。配置它需要三個階段搔耕。

\bullet ?像上面所做的那樣隙袁,使用登錄頁面的URL配置一個LoginLauthenAuthenticationEntryPoint,并將其設(shè)置在ExceptionTranslationFilter上弃榨。

\bullet ?實現(xiàn)登錄頁面(使用JSP或MVC控制器)菩收。

\bullet ?在應(yīng)用程序上下文中配置 UsernamePasswordAuthenticationFilter? 的實例

\bullet ?將過濾器bean添加到您的過濾器鏈代理(確保您關(guān)注順序)。

登錄表單只包含用戶名和密碼輸入字段鲸睛,并發(fā)布到由過濾器監(jiān)控的URL(默認(rèn)為/login)坛梁。基本的過濾器配置如下所示:

<bean id="authenticationFilter" class=

"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">

<property name="authenticationManager" ref="authenticationManager"/>

</bean>

Application Flow on Authentication Success and Failure

過濾器調(diào)用配置的 AuthenticationManager?來處理每個身份驗證請求腊凶。成功身份驗證或身份驗證失敗后的目標(biāo)分別由AuthenticationSuccessHandler?AuthenticationFailureHandler?策略接口控制划咐。過濾器具有允許您設(shè)置屬性拴念,因此您可以完全自定義行為。提供了一些標(biāo)準(zhǔn)實現(xiàn)褐缠,如 SimpleUrlAuthenticationSuccessHandler政鼠、SavedRequestAwareAuthenticationSuccessHandlerSimpleUrlAuthenticationFailureHandler队魏、ExceptionMappingAuthenticationFailureHandler?DelegatingAuthenticationFailureHandler公般。多了解這些類的javadoc,以及?AbstractAuthenticationProcessingFilter?胡桨,了解它們的工作原理和支持的功能官帘。

如果身份驗證成功,則生成的?Authentication?將放入SecurityContextHolder昧谊。然后刽虹,將調(diào)用配置的AuthenticationSuccessHandler?,將用戶重定向或轉(zhuǎn)發(fā)到適當(dāng)?shù)哪繕?biāo)呢诬。默認(rèn)情況下涌哲,會使用SavedRequestAwareAuthenticationSuccessHandler?,這意味著用戶將被重定向到請求登錄之前所請求的原始目標(biāo)尚镰。

ExceptionTranslationFilter?緩存用戶發(fā)出的原始請求阀圾。當(dāng)用戶進(jìn)行身份驗證時,請求處理程序使用此緩存請求獲取原始URL并重定向到該URL狗唉。然后重新構(gòu)建原始請求并將其用作替代請求初烘。

如果身份驗證失敗,將調(diào)用配置的 AuthenticationFailureHandler?分俯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肾筐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子澳迫,更是在濱河造成了極大的恐慌局齿,老刑警劉巖剧劝,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橄登,死亡現(xiàn)場離奇詭異,居然都是意外死亡讥此,警方通過查閱死者的電腦和手機(jī)拢锹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萄喳,“玉大人卒稳,你說我怎么就攤上這事∷蓿” “怎么了充坑?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵减江,是天一觀的道長。 經(jīng)常有香客問我捻爷,道長辈灼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任也榄,我火速辦了婚禮巡莹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甜紫。我一直安慰自己降宅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布囚霸。 她就那樣靜靜地躺著腰根,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邮辽。 梳的紋絲不亂的頭發(fā)上唠雕,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機(jī)與錄音吨述,去河邊找鬼岩睁。 笑死,一個胖子當(dāng)著我的面吹牛揣云,可吹牛的內(nèi)容都是我干的捕儒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼邓夕,長吁一口氣:“原來是場噩夢啊……” “哼刘莹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起焚刚,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤点弯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后矿咕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抢肛,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年碳柱,在試婚紗的時候發(fā)現(xiàn)自己被綠了捡絮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡莲镣,死狀恐怖福稳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瑞侮,我是刑警寧澤的圆,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布鼓拧,位于F島的核電站,受9級特大地震影響越妈,放射性物質(zhì)發(fā)生泄漏毁枯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一叮称、第九天 我趴在偏房一處隱蔽的房頂上張望种玛。 院中可真熱鬧,春花似錦瓤檐、人聲如沸赂韵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祭示。三九已至,卻和暖如春质涛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掰担。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留带饱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓勺疼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親执庐。 傳聞我的和親對象是個殘疾皇子酪耕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容