目錄
- 1. 概述
- 2. 在 Spring 中設置 RestTemplate
- 3. 手動管理 Authorization HTTP 標頭
- 4. 自動管理 Authorization HTTP 標頭
- 5. Maven 依賴
- 6. 結論
1. 概述
在本教程中,我們將學習如何使用 Spring 的 RestTemplate 來 消費使用 Basic 身份驗證保護的 RESTful 服務。
在為模板設置 Basic 身份驗證後,每個請求將被 預先包含所需的完整憑據,以便執行身份驗證過程。憑據將被編碼,並使用 Authorization HTTP 標頭,符合 Basic 身份驗證方案的規範。例如,它可能看起來像這樣:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==2. 設置 RestTemplate
我們可以通過聲明一個 Bean 來將 RestTemplate 啓動到 Spring 上下文中。但是,使用 基本身份驗證設置 RestTemplate 需要手動干預,因此我們不直接聲明 Bean,而是使用 Spring FactoryBean 以獲得更大的靈活性。這個 FactoryBean 在初始化時將創建和配置模板:
@Component
public class RestTemplateFactory
implements FactoryBean<RestTemplate>, InitializingBean {
private RestTemplate restTemplate;
public RestTemplate getObject() {
return restTemplate;
}
public Class<RestTemplate> getObjectType() {
return RestTemplate.class;
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() {
HttpHost host = new HttpHost("localhost", 8082, "http");
restTemplate = new RestTemplate(
new HttpComponentsClientHttpRequestFactoryBasicAuth(host));
}
}主機和端口值應取決於環境,允許客户端為集成測試定義一組值,以及為生產環境使用另一組值。這些值可以通過 Spring 對屬性文件的第一級支持進行管理。
3. 手動管理 Authorization HTTP 標頭
為 Basic 身份驗證創建 Authorization 標頭非常簡單,我們可以通過幾行代碼手動完成:
HttpHeaders createHeaders(String username, String password){
return new HttpHeaders() {{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(Charset.forName("US-ASCII")) );
String authHeader = "Basic " + new String( encodedAuth );
set( "Authorization", authHeader );
}};
}此外,發送請求也非常簡單:
restTemplate.exchange
(uri, HttpMethod.POST, new HttpEntity<T>(createHeaders(username, password)), clazz);4. 自動管理 Authorization HTTP Header
Spring 3.0、3.1 以及現在 4.x 版本都對 Apache HTTP 庫提供了良好的支持:
- 在 Spring 3.0 中,CommonsClientHttpRequestFactory 集成了已過生命週期 (HttpClient 3.x)。
- Spring 3.1 引入了通過 HttpComponentsClientHttpRequestFactory 支持當前 HttpClient 4.x (通過 JIRA SPR-6180 添加的支持)。
- Spring 4.0 通過 HttpComponentsAsyncClientHttpRequestFactory 引入了異步支持。
現在我們開始配置使用 HttpClient 4 和 Spring 4。
RestTemplate 需要一個支持 Basic 身份驗證的 HTTP 請求工廠。但是,直接使用現有的 HttpComponentsClientHttpRequestFactory 會比較困難,因為 RestTemplate 的架構沒有充分支持 HttpContext,這對於解決問題至關重要。因此,我們需要對 HttpComponentsClientHttpRequestFactory 進行子類化並覆蓋 createHttpContext 方法:
public class HttpComponentsClientHttpRequestFactoryBasicAuth
extends HttpComponentsClientHttpRequestFactory {
HttpHost host;
public HttpComponentsClientHttpRequestFactoryBasicAuth(HttpHost host) {
super();
this.host = host;
}
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
return createHttpContext();
}
private HttpContext createHttpContext() {
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
authCache.put(host, basicAuth);
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(HttpClientContext.AUTH_CACHE, authCache);
return localcontext;
}
}我們在此實現了基本的身份驗證支持,包括在 HttpContext 的創建中。正如您所見,使用 HttpClient 4.x 進行預先身份驗證確實給我們帶來了一定的負擔。身份驗證信息被緩存,並且手動設置和管理此身份驗證緩存對於我們來説非常複雜且不直觀。
現在一切都已就緒,RestTemplate 只要添加一個 BasicAuthorizationInterceptor 就能支持 Basic Authentication 方案。
restTemplate.getInterceptors().add(
new BasicAuthorizationInterceptor("username", "password"));然後是請求:
restTemplate.exchange(
"http://localhost:8082/spring-security-rest-basic-auth/api/foos/1",
HttpMethod.GET, null, Foo.class);要就如何安全地保護 REST 服務進行深入討論,請查看這篇文章。
5. Maven 依賴
我們需要以下 Maven 依賴項,用於 <em>RestTemplate</em> 本身以及 HttpClient 庫:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.13</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>如果手動構建 HTTP Authorization 標頭,則需要額外的庫來支持編碼:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>我們可以在 Maven 倉庫中找到最新版本:spring-webmvc,httpclient5 和 commons-codec。
6. 結論
關於 RestTemplate 和安全性的信息,很多都未能充分考慮當前的 HttpClient 4.x 版本,儘管 3.x 分支已停止維護,Spring 對該版本的支持也已完全廢棄。 在本文中,我們試圖通過對如何使用 RestTemplate 進行詳細、分步討論,來解決這個問題,並演示如何使用它來消費受保護的 REST API。
這是一個基於 Maven 的項目,因此可以輕鬆導入和運行。