爲一個REST服務使用Spring Security的基本和摘要認證

原創翻譯自:http://www.baeldung.com/2011/11/20/basic-and-digest-authentication-for-a-restful-service-with-spring-security-3-1/ java

1. 簡介 git

    這篇文章討論的是如何在一個相同URI結構的REST API上使用基礎和摘要式的認證。在一篇從前的文章裏,咱們討論了另外一種保護REST服務的方法----表單爲基礎的認證,可是基礎的和摘要式的認證是另外一個更天然的方式,也是更RESTful的一種。 github

2. 基礎認證的配置 web

    表單爲基礎的認證不是RESTful服務的一個合適認證方式的主要緣由是Spring Security將會使用Sessions -- 這固然是一個服務器的狀態,因此REST服務是一種無狀態的服務這一原則其實是被違背了。 spring

    咱們將開始設置基礎認證 -- 首先咱們從主要的<http> security 元素中移除老的自定義入口和過濾器, shell

<http create-session="stateless">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />
 
   <http-basic />
</http>

    注意如何增長簡單的一行配置<http-basic />來開啓基礎認證 -- 它是處理建立和裝配BasicAuthenticationFilter BasicAuthenticationEntryPoint。 api

2.1. 知足無狀態的約束 - 擺脫sessions 安全

    RESTful風格一個主要的約束就是客戶與服務器的通信是徹底無狀態的(stateless),就像論文中寫的: 服務器

    5.1.3 無狀態 restful

    咱們接下來增長一條客戶端-服務器交互的約束: 通信必須是無狀態的,在章節3.4.3中的無狀態的 客戶端-服務器風格里,每一次從客戶端到服務器的請求必須包含全部必須的信息來理解此請求,而且不能使用任何存儲在服務器中的內容。Session狀態所以必須完整的保持在客戶端上。

    服務器中的Session在Spring Security中是一個歷史悠久的概念,想要徹底的移除它如今看來是很困難的,特別是當配置命名空間時。然而,Spring Security 3.1爲session的建立擴展了一個新的無狀態的命名空間(namespace)選項,這能夠有效地保證Spring的無session化。這個新選項的做用是在security filter chain相關的filters中徹底移除全部的session,保證每個請求都會進行身份認證。

3. 配置摘要式認證

    接着前邊的配置繼續,filter entry point 須要設置摘要式認證的定義beans。而後,digest entry point將會在後臺覆蓋<http-basic>建立的entry point。最後,自定義的digest filter將會織入到security filter chain,直接放置在基礎認證過濾的後邊。

<http create-session="stateless" entry-point-ref="digestEntryPoint">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />
 
   <http-basic />
   <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>
 
<beans:bean id="digestFilter" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
   <beans:property name="userDetailsService" ref="userService" />
   <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" />
</beans:bean>
 
<beans:bean id="digestEntryPoint" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
   <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/>
   <beans:property name="key" value="acegi" />
</beans:bean>
 
<authentication-manager>
   <authentication-provider>
      <user-service id="userService">
         <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" />
         <user name="user" password="user" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>
    不幸的是,沒有像配置基礎認證使用<http-basic>同樣的命名空間方式來配置摘要式認證。正因如此,必要的beans不得不被手工定義和裝配到security 配置中。

4. 在一個RESTful服務中同時支持兩種認證協議

    單獨的基礎認證和摘要認證能夠很容易地被 Spring Security 3.x實現;它也支持在同一個RESTful服務中同時使用,在同一個URI中進行映射提高了配置和測試這個服務的複雜性。

4.1. 匿名請求

    在 security chain中同時使用基礎和摘要認證的狀況下,匿名請求的方式 --- 一種不包含任何認證憑據的請求 (Authorization HTTP header) --- 被Spring Security處理 --- 兩種認證過濾會找不到任何憑據並繼續執行過濾鏈。而後,咱們會看到一個請求若是沒有認證經過,一個AccessDeniedException 會被拋出並獲取在ExceptionTranslationFilter中,跳轉到摘要入口,提示客戶端輸入憑據。

    基礎認證和摘要認證的功能是很是有限的,若是不能定義請求中認證憑據的類型他們會繼續執行安全過濾鏈。因此 Spring Security能夠很是靈活的在同一URI上配置多重認證協議配置。

    當一個請求包含正確的認證憑據時 - 基礎的或者摘要的 - 協議均可以被正確的使用。然而,任何匿名的請求,客戶端將會被提示摘要認證憑據。這事由於摘要入口被配置爲主要的、單一的 Spring Security入口;因此,摘要認證能夠被考慮爲默認的認證入口。

4.2. 帶認證憑據的請求

    基礎認證定義一個帶憑據的請求是經過Authorization中帶「Basic」前綴的請求頭。當處理這樣一個請求時,憑據將會被解碼到基礎認證過濾器中而且請求將會被認證。相似的,一個帶憑據的摘要請求使用的是帶「Digest」前綴的Authorization 請求頭。

5. 測試上面的場景

    測試將會消費REST服務,經過在基礎/摘要認證後建立的一個新資源:


@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 ) );
}
    注意這些測試優先增長憑據到請求中來使用基礎認證,不論服務端是否以認證發起盤問。這保證了服務器不須要盤問客戶端的憑據,由於若是它盤問了,盤問將會致使摘要的認證,覺得這事默認的認證方式。


6. 結論

    這篇文章覆蓋了爲RESTful服務配置和實現基礎認證和摘要認證,使用了大多數的Spring Security 3.0命名空間支持和一些 by Spring Security 3.1新增的新特性。

    查看完整的實現,請 check out the github project.

相關文章
相關標籤/搜索