1. Обзор
В этой статье рассмотрим, как использовать Spring'овый RestTemplate
для работы с RESTful-сервисами, защищенными Basic Authentication.
После настройки RestTemplate
для работы с Basic Authentication
все запросы будут содержать учетные данные, необходимые для выполнения процесса аутентификации. Данные для аутентификации кодируются и записываются в HTTP-заголовок Authorization
, который выглядит следующим образом:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
2. Настройка RestTemplate
Для получения RestTemplate
в контексте Spring, достаточно объявить его как бин. Но Basic Authentication требует ручной конфигурации, поэтому будем использовать 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));
}
}
Параметры host и port обычно зависят от окружения: у клиента должна быть возможность определять один набор значений, например, для интеграционного тестирования, а другой для продакшена. Эти значения можно задавать через файлы свойств.
3. Ручное управление HTTP-заголовком Authorization
Заголовок 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. Автоматическое управление HTTP-заголовком Authorization
В Spring 3.0 и 3.1, а теперь и в 4.x встроена хорошая поддержка библиотек Apache HTTP:
В Spring 3.0
CommonsClientHttpRequestFactory
интегрирован с ныне устаревшим HttpClient 3.x.В Spring 3.1 появилась поддержка текущего HttpClient 4.x через
HttpComponentsClientHttpRequestFactory
(JIRA SPR-6180).В Spring 4.0 появилась поддержка асинхронности через
HttpComponentsAsyncClientHttpRequestFactory
.
Давайте начнем настройку с HttpClient 4 и Spring 4.
Для RestTemplate потребуется фабрика HTTP-запросов, поддерживающая Basic Authentication. Однако напрямую использовать существующий 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
мы добавляем поддержку Basic Authentication. Как видно, упреждающая Basic Authentication с помощью HttpClient 4.x немного обременительна. Информация об аутентификации кэшируется, но настроить вручную этот кэш аутентификации сложно и не интуитивно.
Далее просто добавляем BasicAuthorizationInterceptor
в RestTemplate:
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 для самого RestTemplate и библиотеки HttpClient:
<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-заголовок Authorization вручную, то нам также потребуется дополнительная библиотека для поддержки кодирования:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
6. Заключение
Большинство информации, которую можно найти по RestTemplate
и безопасности, все еще не учитывает текущие релизы HttpClient 4.x, даже несмотря на то, что ветка 3.x устарела и Spring'ом не поддерживается. В этой статье мы немного восполнили этот пробел, описав, как настроить Basic Authentication для RestTemplate, и использовать его для запросов к защищенному REST API.
Полный пример кода с RESTful-сервисом вы можете найти на Github.
Все разработчики проходят одинаковый путь в развитии. Приглашаем всех желающих на demo-занятие «Послание про архитектуру приложений самому себе в прошлое», на котором преподаватель OTUS Виталий Куценко расскажет, как избежать нескольких ошибок, которые могут сильно усложнить развитие приложения. Регистрация по ссылке.