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

OAuth2.0 и динамическая регистрация клиентов (с использованием устаревшего стека Spring Security OAuth)

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

1. Введение

В этом руководстве мы собираемся подготовить динамическую регистрацию клиента с помощью протокола OAuth2.0. OAuth2.0 — это структура авторизации, которая позволяет получить ограниченный доступ к учетным записям пользователей в службе HTTP. Клиент OAuth2.0 — это приложение, которое хочет получить доступ к учетной записи пользователя. Этот клиент может быть внешним веб-приложением, пользовательским агентом или просто собственным клиентом.

Чтобы добиться динамической регистрации клиентов, мы собираемся хранить учетные данные в базе данных, а не в жестко заданной конфигурации. Приложение, которое мы собираемся расширить, изначально было описано в учебнике Spring REST API + OAuth2 .

Примечание . В этой статье используется устаревший проект Spring OAuth .

2. Зависимости Maven

Сначала мы настроим следующий набор зависимостей:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>

Обратите внимание, что мы используем spring-jdbc , потому что собираемся использовать БД для хранения новых зарегистрированных пользователей с паролями.

3. Конфигурация сервера OAuth2.0

Во-первых, нам нужно настроить наш сервер авторизации OAuth2.0. Основная конфигурация находится внутри следующего класса:

@Configuration
@PropertySource({ "classpath:persistence.properties" })
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig
extends AuthorizationServerConfigurerAdapter {

// config
}

Нам нужно настроить несколько основных вещей; начнем с ClientDetailsServiceConfigurer:

@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource())

// ...
}

Это позволит убедиться, что мы используем постоянство для получения информации о клиенте.

Давайте, конечно, настроим этот стандартный источник данных:

@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();

dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}

Итак, теперь наше приложение будет использовать базу данных в качестве источника зарегистрированных клиентов, вместо типичных жестко запрограммированных в памяти клиентов.

4. Схема БД

Давайте теперь определим структуру SQL для хранения наших клиентов OAuth:

create table oauth_client_details (
client_id VARCHAR(256) PRIMARY KEY,
resource_ids VARCHAR(256),
client_secret VARCHAR(256),
scope VARCHAR(256),
authorized_grant_types VARCHAR(256),
web_server_redirect_uri VARCHAR(256),
authorities VARCHAR(256),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additional_information VARCHAR(4096),
autoapprove VARCHAR(256)
);

Наиболее важные поля из oauth_client_details , на которых мы должны сосредоточиться:

  • client_id — для хранения id вновь зарегистрированных клиентов
  • client_secret — для хранения паролей клиентов
  • access_token_validity — указывает, действителен ли клиент .
  • полномочия — указать, какие роли разрешены для конкретного клиента
  • объем — разрешенные действия, например написание статусов в Facebook и т. д.
  • author_grant_types , который предоставляет информацию о том, как пользователи могут войти в конкретный клиент (в нашем примере это форма входа с паролем)

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

5. Давайте сохраним некоторых клиентов

С определением схемы SQL мы, наконец, можем создать некоторые данные в системе — и, по сути, определить клиента.

Мы собираемся использовать следующий скрипт data.sql , который Spring Boot будет запускать по умолчанию, для инициализации БД:

INSERT INTO oauth_client_details
(client_id, client_secret, scope, authorized_grant_types,
web_server_redirect_uri, authorities, access_token_validity,
refresh_token_validity, additional_information, autoapprove)
VALUES
("fooClientIdPassword", "secret", "foo,read,write,
"password,authorization_code,refresh_token", null, null, 36000, 36000, null, true);

Описание наиболее важных полей в oauth_client_details приведено в предыдущем разделе.

6. Тестирование

Чтобы протестировать динамическую регистрацию клиента, нам нужно запустить проекты spring-security-oauth-server и spring-security-oauth-resource на портах 8081 и 8082 соответственно.

Теперь мы, наконец, можем написать несколько живых тестов.

Предположим, что мы зарегистрировали клиента с идентификатором fooClientIdPassword , который имеет доступ для чтения foos.

Во-первых, мы попытаемся получить токен доступа с сервера аутентификации, используя уже определенный клиент:

@Test
public void givenDBUser_whenRevokeToken_thenAuthorized() {
String accessToken = obtainAccessToken("fooClientIdPassword", "john", "123");

assertNotNull(accessToken);
}

А вот и логика получения Access Token:

private String obtainAccessToken(String clientId, String username, String password) {
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type", "password");
params.put("client_id", clientId);
params.put("username", username);
params.put("password", password);
Response response = RestAssured.given().auth().preemptive()
.basic(clientId, "secret").and().with().params(params).when()
.post("http://localhost:8081/spring-security-oauth-server/oauth/token");
return response.jsonPath().getString("access_token");
}

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

В этом руководстве мы узнали, как динамически регистрировать неограниченное количество клиентов с помощью платформы OAuth2.0.

Полную реализацию этого руководства можно найти на GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.

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