使用RestTemplate进行基本身份验证

2023/05/17

1. 概述

在本教程中,我们介绍如何使用Spring的RestTemplate来使用由基本身份验证保护的RESTful服务

一旦我们为RestTemplate设置了基本身份验证,每个请求都将被抢先发送,其中包含执行身份验证过程所需的完整凭据。凭据将根据基本身份验证方案的规范进行编码,并使用Authorization HTTP头,如下所示:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

2.设置RestTemplate

我们可以简单地通过为RestTemplate声明一个bean来将RestTemplate引导到Spring上下文中;但是,使用基本身份验证设置RestTemplate需要手动干预,因此我们将使用Spring FactoryBean来实现更大的灵活性,而不是直接声明bean。这个FactoryBean将在初始化时创建和配置RestTemplate:

@Component
public class RestTemplateFactory implements FactoryBean<RestTemplate>, InitializingBean {
	private RestTemplate restTemplate;

	public RestTemplateFactory() {
		super();
	}

	@Override
	public RestTemplate getObject() {
		return restTemplate;
	}

	@Override
	public Class<RestTemplate> getObjectType() {
		return RestTemplate.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

	@Override
	public void afterPropertiesSet() {
		HttpHost host = new HttpHost("localhost", 8082, "http");
		final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryBasicAuth(host);
	}
}

主机和端口值应取决于环境,允许客户端灵活地定义一组值用于集成测试,另一组值用于生产使用。这些值可以由Spring对属性文件的第一类支持来管理。

3. Authorization HTTP Header的手动管理

为基本身份验证创建Authorization标头对我们来说相当简单,因此我们可以通过几行代码手动完成:

HttpHeaders createHeaders(String username, String password){
   return new HttpHeaders() ;
}

此外,发送请求同样简单:

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的支持(在JIRASPR-6180中添加了支持)。
  • Spring 4.0通过HttpComponentsAsyncClientHttpRequestFactory引入了异步支持。

让我们开始使用HttpClient 4和Spring 4进行设置。

RestTemplate需要一个支持基本身份验证的HTTP请求工厂,然而,直接使用现有的HttpComponentsClientHttpRequestFactory将被证明是困难的,因为RestTemplate的体系结构在设计时没有对HttpContext提供良好的支持,而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);

5. Maven依赖

对于RestTemplate本身和HttpClient库,我们需要以下Maven依赖项:

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.3.13</version>
</dependency>

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.13</version>
</dependency>

或者,如果我们手动构建HTTP Authorization标头,那么我们需要一个额外的库来支持编码:

<dependency>
   <groupId>commons-codec</groupId>
   <artifactId>commons-codec</artifactId>
   <version>1.10</version>
</dependency>

6. 总结

在RestTemplate和安全性上可以找到的许多信息仍然不能解释当前的HttpClient 4.x版本,即使3.x分支已经过时,Spring对该版本的支持也被完全弃用。在本文中,我们试图通过详细的、逐步的讨论来改变这一点,讨论如何使用RestTemplate设置基本身份验证并使用它来使用安全的REST API。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章