使用Spring Security REST服務的基本/Digest身份驗證
案例概述
本文討論如何在REST API的相同URI結構上設置基本身份驗證和Digest身份驗證。在前一篇文章中,我們討論了另一種保護REST服務的方法 - 基於表單的身份驗證,因此Basic和Digest身份驗證是自然的替代方案,也是更RESTful的身份驗證方法。
基本的認證配置
基於表單的身份驗證不適合RESTful服務的主要原因是Spring Security將使用Sessions - 這當然是服務器上的狀態,因此REST中的無狀態約束幾乎被忽略。
我們首先設置基本身份驗證 - 首先我們從主
```xml
請注意,如何使用單個配置行添加對基本身份驗證的支持 -
滿足無狀態約束—擺脱Session
RESTful架構風格的主要限制之一是客户端 - 服務器通信是完全無狀態的,正如原始論文所示:
5.1.3 無狀態:
接下來我們為客户端 - 服務器交互添加一個約束:通信本質上必須是無狀態的,如3.4.3節(圖5-3)的客户端無狀態服務器(CSS)樣式,這樣每個請求從客户端到服務器必須包含理解請求所需的所有信息,並且不能利用服務器上任何存儲的上下文。因此,會話狀態完全保留在客户端上。
服務器上的Session概念在Spring Security中具有悠久的歷史,並且直到現在才完全刪除它,尤其是在使用命名空間完成配置時。
但是,Spring Security 使用新的無狀態選項增強了命名空間配置,從而有效地保證Spring不會創建或使用任何會話。此新選項的作用是從安全篩選器鏈中刪除所有與會話相關的篩選器,確保對每個請求執行身份驗證。
Digest式身份驗證的配置
從先前的配置開始,設置Digest式身份驗證所需的過濾器和入口點將被定義為bean。然後,Digest入口點將覆蓋由幕後的
```xml
遺憾的是,安全命名空間中不支持自動配置Digest式身份驗證,這與使用
在同一RESTful服務中支持兩種身份驗證協議
僅在Spring Security中可以輕鬆實現基本或Digest式身份驗證; 它支持同一個RESTful Web服務,在相同的URI映射上為服務的配置和測試引入了新的複雜性。
匿名請求
通過安全鏈中的基本和Digest過濾器,Spring Security處理匿名請求(不包含身份驗證憑據的請求(授權HTTP標頭))的方式是 - 兩個身份驗證過濾器將找不到憑據並將繼續執行過濾鏈。然後,查看請求未經過身份驗證的方式,拋出AccessDeniedException並將其捕獲到ExceptionTranslationFilter中,該ExceptionTranslationFilter將啟動Digest入口點,提示客户端提供憑據。
基本和Digest過濾器的職責非常狹窄 - 如果他們無法識別請求中的身份驗證憑據類型,他們將繼續執行安全過濾器鏈。正因為如此,Spring Security可以靈活地配置在同一URI上支持多個身份驗證協議。
當請求包含正確的身份驗證憑據(基本或Digest)時,將正確使用該協議。但是,對於匿名請求,將僅提示客户端提取Digest身份驗證憑據。這是因為Digest入口點被配置為Spring Security鏈的主要和單個入口點; 因為這樣的Digest認證可以被認為是默認的。
請求身份驗證憑據
具有基本身份驗證憑據的請求將由以“Basic”前綴開頭的Authorization標頭標識。在處理這樣的請求時,憑證將在基本認證過濾器中被解碼,並且該請求將被授權。同樣,具有Digest式身份驗證憑據的請求將使用前綴“Digest”作為其授權標頭。
測試兩種情況
在使用基本或Digest進行身份驗證後,測試將通過創建新資源來使用REST服務:
```java @Test public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){ // Given // When Response response = given() .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD ) .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) ) .post( paths.getFooURL() );
// Then assertThat( response.getStatusCode(), is( 201 ) ); } @Test public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){ // Given // When Response response = given() .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD ) .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) ) .post( paths.getFooURL() );
// Then assertThat( response.getStatusCode(), is( 201 ) ); } ```
請注意,使用基本身份驗證的測試無論服務器是否已經過驗證都會搶先向請求添加憑據。這是為了確保服務器不需要向客户端請求憑證,因為這樣,才會使用摘要憑證,這是默認值。
案例結論
本文介紹了RESTful服務的Basic和Digest身份驗證的配置和實現,主要使用Spring Security命名空間支持以及框架中的一些新功能。