1. 概述
本教程將演示如何設置、配置和自定義 Spring 中的 Digest 身份驗證。 類似於之前介紹 Basic 身份驗證的文章,我們將在此基礎上,利用 Spring Security 提供的 Digest 身份驗證機制,對應用程序進行安全保護。
Digest 身份驗證 是 Basic 身份驗證的改進,旨在解決先前身份驗證機制中的問題,確保憑據在網絡傳輸過程中不會以明文形式發送。
2. 安全 XML 配置
要理解配置的本質是,雖然 Spring Security 提供了對 Digest 認證機制的完整原生支持,但這種支持與 Basic 認證相比,在命名空間中的集成程度並不高。
在這種情況下,我們需要手動定義構成安全配置的原始 Bean,即 DigestAuthenticationFilter 和 DigestAuthenticationEntryPoint。
<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>
<!-- the security namespace configuration -->
<http use-expressions="true" entry-point-ref="digestEntryPoint">
<intercept-url pattern="/**" access="isAuthenticated()" />
<custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>
<authentication-manager>
<authentication-provider>
<user-service id="userService">
<user name="user1" password="user1Pass" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>接下來,我們需要將這些 Bean 集成到整體安全配置中——並且在此情況下,命名空間仍然足夠靈活,允許我們這樣做。
第一部分是通過將自定義入口 Bean 指向,通過主 <http> 元素的 <em>entry-point-ref</em> 屬性。
第二部分是添加新定義的 Digest 過濾器到安全過濾器鏈中。由於此過濾器在功能上與 <em>BasicAuthenticationFilter</em> 相同,因此我們在鏈中的相對位置保持不變——這通過整體中 <em>BASIC_AUTH_FILTER</em> 別名指定。
最後,請注意,Digest 過濾器配置為指向用户服務 Bean——並且在此,命名空間再次非常有用,因為它允許我們為由 <user-service> 元素創建的默認用户服務指定 Bean 名稱:
<user-service id="userService">3. 調用安全應用
我們將使用 curl 命令來調用安全應用並瞭解客户端如何與之交互。
首先,我們請求主頁 – 在請求中不提供安全憑據。
curl -i http://localhost/spring-security-mvc-digest-auth/homepage.html正如預期的那樣,我們收到了一個狀態碼為 401 未授權 的響應。
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=CF0233C...; Path=/spring-security-mvc-digest-auth/; HttpOnly
WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="auth",
nonce="MTM3MzYzODE2NTg3OTo3MmYxN2JkOWYxZTc4MzdmMzBiN2Q0YmY0ZTU0N2RkZg=="
Content-Type: text/html;charset=utf-8
Content-Length: 1061
Date: Fri, 12 Jul 2013 14:04:25 GMT如果該請求是由瀏覽器發送的,認證挑戰將提示用户使用簡單的用户名/密碼對話框輸入憑據。
現在,讓我們提供正確的憑據並再次發送請求:
curl -i --digest --user
user1:user1Pass http://localhost/spring-security-mvc-digest-auth/homepage.html請注意,我們通過使用 curl 命令的 –digest 標誌啓用了摘要身份驗證。
服務器的第一個響應將保持不變——即 401 Unauthorized 錯誤——但現在挑戰將通過第二個請求進行解釋和處理,該請求將成功返回 200 OK。
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=A961E0D...; Path=/spring-security-mvc-digest-auth/; HttpOnly
WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="auth",
nonce="MTM3MzYzODgyOTczMTo3YjM4OWQzMGU0YTgwZDg0YmYwZjRlZWJjMDQzZWZkOA=="
Content-Type: text/html;charset=utf-8
Content-Length: 1061
Date: Fri, 12 Jul 2013 14:15:29 GMT
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=55F996B...; Path=/spring-security-mvc-digest-auth/; HttpOnly
Content-Type: text/html;charset=ISO-8859-1
Content-Language: en-US
Content-Length: 90
Date: Fri, 12 Jul 2013 14:15:29 GMT
<html>
<head></head>
<body>
<h1>This is the homepage</h1>
</body>
</html>最後,需要注意的是,客户端可以在首次請求中主動發送正確的 Authorization 標頭,從而完全避免服務器的安全挑戰以及第二次請求。
以下是響應參數的解釋:
- realm:定義了用於 Web 或應用程序服務器的安全策略域。服務器上的受保護資源可以劃分為一組保護空間,每個空間具有自己的身份驗證方案和/或授權數據庫,其中包含用户和組的集合。
- nonce:是一種白名單機制,服務器會在每次頁面請求中生成一個唯一的隨機字符串。通過使用此屬性,您可以僅允許具有正確值的嵌入式腳本或樣式執行,從而為攻擊者提供了一條難以攻擊的方式。
- qop:保護質量,其值可以是“auth”。
4. Maven 依賴
Spring Security 的安全依賴將在 Spring Security Maven 教程中進行深入討論。簡而言之,我們需要在我們的 pom.xml 文件中將 spring-security-web 和 spring-security-config 定義為依賴項。
5. 結論
在本教程中,我們通過利用框架中的 Digest 身份驗證支持,將安全性引入了一個簡單的 Spring MVC 項目。
當項目在本地運行時,主頁 HTML 可通過以下鏈接訪問(或,通過最小的 Tomcat 配置,在端口 8080 上):
http://localhost:8080/spring-security-mvc-digest-auth/homepage.html
最終,應用程序無需選擇 Basic 和 Digest 身份驗證之間 – 兩者都可以同時在相同的 URI 結構上配置,從而使客户端能夠在消費 Web 應用程序時選擇使用兩種機制。