RestTemplate的基本身份验证
1. 概述
在本教程中,我们将学习如何使用 Spring 的RestTemplate来使用受基本身份验证保护的 RESTful 服务。
一旦我们为模板设置了基本身份验证,每个请求都将被抢先发送,其中包含执行身份验证过程所需的**完整凭据。**凭据将根据基本身份验证方案的规范进行编码,并使用Authorization HTTP Header。一个例子看起来像这样:
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 Header的手动管理
为基本身份验证创建授权标头对我们来说相当简单,因此我们可以使用几行代码手动完成:
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需要一个支持基本身份验证的 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 来支持基本身份验证方案:
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依赖
对于RestTemplate本身和 HttpClient 库,我们需要以下 Maven 依赖项:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
或者,如果我们手动构造 HTTP授权标头,那么我们将需要一个额外的库来支持编码:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
我们可以在 Maven 存储库中找到spring-webmvc 、httpclient 和commons-codec 版本。