使用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名稱空間支援以及框架中的一些新功能。