Перейти к основному содержимому

Базовая и дайджест-аутентификация для службы REST с Spring Security

· 6 мин. чтения

Оглавление

1. Обзор

В этой статье обсуждается, как настроить базовую и дайджест-аутентификацию в одной и той же структуре URI REST API . В предыдущей статье мы обсуждали другой метод защиты службы REST — аутентификацию на основе форм , поэтому обычная и дайджест-аутентификация являются естественной альтернативой, а также более RESTful.

2. Настройка базовой аутентификации

Основная причина того, что аутентификация на основе форм не идеальна для службы RESTful, заключается в том, что Spring Security будет использовать сеансы — это, конечно, состояние на сервере, поэтому ограничения отсутствия состояния в REST практически игнорируются.

Мы начнем с настройки базовой аутентификации — сначала мы удалим старую пользовательскую точку входа и фильтр из основного элемента безопасности <http> :

<http create-session="stateless">
<intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

<http-basic />
</http>

Обратите внимание, как добавлена поддержка базовой аутентификации с помощью одной строки конфигурации — <http-basic /> — которая обрабатывает создание и связывание как BasicAuthenticationFilter , так и BasicAuthenticationEntryPoint .

2.1. Удовлетворение ограничения без сохранения состояния — избавление от сессий

Одним из основных ограничений архитектурного стиля RESTful является то, что взаимодействие клиент-сервер полностью не имеет состояния , как гласит исходная диссертация :

5.1.3 Без гражданства Затем мы добавим ограничение на взаимодействие клиент-сервер: связь должна быть по своей природе без сохранения состояния, как в стиле клиент-сервер без сохранения состояния (CSS) в разделе 3.4.3 (рис. 5-3), чтобы каждый запрос от клиента к server должен содержать всю информацию, необходимую для понимания запроса, и не может использовать какой-либо сохраненный контекст на сервере. Таким образом, состояние сеанса полностью сохраняется на клиенте .

Концепция сеанса на сервере имеет долгую историю в Spring Security, и полностью удалить ее до сих пор было сложно, особенно когда конфигурация выполнялась с использованием пространства имен.

Однако Spring Security дополняет конфигурацию пространства имен новой опцией без сохранения состояния для создания сеанса, которая эффективно гарантирует, что Spring не будет создавать или использовать сеанс. Эта новая опция полностью удаляет все фильтры, связанные с сеансом, из цепочки фильтров безопасности, гарантируя, что аутентификация выполняется для каждого запроса.

3. Настройка дайджест-аутентификации

Начиная с предыдущей конфигурации, фильтр и точка входа, необходимые для настройки дайджест-аутентификации, будут определяться как bean-компоненты. Затем точка входа дайджеста переопределит точку входа, созданную <http-basic> за кулисами. Наконец, настраиваемый дайджест-фильтр будет введен в цепочку фильтров безопасности с использованием семантики after пространства имен безопасности, чтобы расположить его непосредственно после основного фильтра проверки подлинности.

<http create-session="stateless" entry-point-ref="digestEntryPoint">
<intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

<http-basic />
<custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>

<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>

<authentication-manager>
<authentication-provider>
<user-service id="userService">
<user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>

К сожалению, в пространстве имен безопасности нет поддержки для автоматической настройки дайджест-аутентификации так, как можно настроить обычную аутентификацию с помощью <http-basic> . Из-за этого необходимые bean-компоненты должны были быть определены и вручную подключены к конфигурации безопасности.

4. Поддержка обоих протоколов аутентификации в одной и той же службе Restful

В Spring Security можно легко реализовать только базовую или дайджест-аутентификацию; он поддерживает оба из них для одной и той же веб-службы RESTful с одними и теми же сопоставлениями URI, что вводит новый уровень сложности в настройку и тестирование службы.

4.1. Анонимный запрос

Как с базовыми, так и с дайджест-фильтрами в цепочке безопасности анонимный запрос — запрос, не содержащий учетных данных аутентификации ( заголовок HTTP авторизации ) — обрабатывается Spring Security так: два фильтра аутентификации не найдут учетных данных и продолжат выполнение цепочка фильтров. Затем, видя, что запрос не был аутентифицирован, генерируется исключение AccessDeniedException и перехватывается в ExceptionTranslationFilter , который запускает точку входа дайджеста, запрашивая у клиента учетные данные.

Обязанности как основного, так и дайджест-фильтра очень узкие — они будут продолжать выполнять цепочку фильтров безопасности, если не смогут идентифицировать тип учетных данных аутентификации в запросе. Именно поэтому Spring Security может гибко настраивать поддержку нескольких протоколов аутентификации для одного и того же URI.

Когда делается запрос, содержащий правильные учетные данные для аутентификации — базовые или дайджест — этот протокол будет использоваться правильно. Однако для анонимного запроса клиенту будет предложено ввести только учетные данные дайджест-аутентификации. Это связано с тем, что точка входа дайджеста настроена как основная и единственная точка входа в цепочку Spring Security; поскольку такая дайджест-аутентификация может считаться используемой по умолчанию .

4.2. Запрос с учетными данными аутентификации

Запрос с учетными данными для базовой аутентификации будет идентифицирован заголовком авторизации , начинающимся с префикса «Basic» . При обработке такого запроса учетные данные будут декодированы в фильтре базовой аутентификации, и запрос будет авторизован. Точно так же запрос с учетными данными для дайджест-аутентификации будет использовать префикс «Дайджест» для заголовка авторизации .

5. Тестирование обоих сценариев

Тесты будут использовать службу REST, создавая новый ресурс после аутентификации либо с помощью Basic, либо с помощью дайджеста:

@Test
public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){
// Given
// When
Response response = given()
.auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD )
.contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
.post( paths.getFooURL() );

// Then
assertThat( response.getStatusCode(), is( 201 ) );
}
@Test
public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){
// Given
// When
Response response = given()
.auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD )
.contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
.post( paths.getFooURL() );

// Then
assertThat( response.getStatusCode(), is( 201 ) );
}

Обратите внимание, что тест, использующий базовую аутентификацию, предварительно добавляет учетные данные к запросу , независимо от того, запрашивал ли сервер аутентификацию или нет. Это делается для того, чтобы серверу не нужно было запрашивать у клиента учетные данные, потому что в противном случае вызов был бы для учетных данных дайджеста, поскольку это значение по умолчанию.

6. Заключение

В этой статье были рассмотрены настройка и реализация как базовой, так и дайджест-аутентификации для службы RESTful с использованием в основном поддержки пространства имен Spring Security, а также некоторых новых функций в инфраструктуре.