1. Обзор
В этом руководстве мы сосредоточимся на том, как протестировать службу REST, которая защищена и использует Keycloak для аутентификации и авторизации с помощью пользовательского интерфейса Swagger.
2. Вызов
Как и другие веб-ресурсы, REST API часто защищены. Таким образом, потребитель службы (такой как пользовательский интерфейс Swagger) должен не только сам обрабатывать HTTP-вызов, но и предоставлять информацию для аутентификации поставщику службы.
Keycloak — это сервер IAM, который позволяет выполнять аутентификацию и авторизацию за пределами реализации поставщика услуг. Это часть архитектуры, как показано на следующей диаграмме:
Как мы видим, и поставщику услуг, и потребителю услуг необходимо обращаться к серверу Keycloak. Во-первых, нам нужно установить сервер Keycloak и интегрировать его в приложение Spring Boot в качестве поставщика услуг REST. Затем нам нужно расширить пользовательский интерфейс Swagger.
3. Настройка пользовательского интерфейса Swagger
Мы могли бы напрямую расширить пользовательский интерфейс Swagger, включив скрипт, подобный этому, в HTML:
<script src="keycloak/keycloak.js"></script>
<script>
var keycloak = Keycloak('keycloak.json');
keycloak.init({ onLoad: 'login-required' })
.success(function (authenticated) {
console.log('Login Successful');
window.authorizations.add("oauth2", new ApiKeyAuthorization("Authorization", "Bearer " + keycloak.token, "header"));
}).error(function () {
console.error('Login Failed');
window.location.reload();
}
);
</script>
Скрипт доступен в виде пакета NPM , поэтому можно было бы разветвить репозиторий исходного кода пользовательского интерфейса Swagger и расширить проект соответствующей зависимостью.
4. Использование стандартов
Расширение пользовательского интерфейса Swagger с помощью кода, специфичного для поставщика, целесообразно только в очень особых случаях. Таким образом, мы должны предпочесть использование независимых от поставщиков стандартов . В следующих разделах будет описано, как это реализовать.
4.1. Существующие стандарты
Во-первых, нам нужно знать, какие стандарты существуют. Для аутентификации и авторизации есть такой протокол, как OAuth2 . Для SSO мы могли бы использовать OpenID Connect (OIDC) в качестве расширения для OAuth2 .
Стандартом описания REST API является OpenAPI . Этот стандарт включает определение нескольких схем безопасности , включая OAuth2 и OIDC:
paths:
/api/v1/products:
get:
...
security:
- my_oAuth_security_schema:
- read_access
...
securitySchemes:
my_oAuth_security_schema:
type: oauth2
flows:
implicit:
authorizationUrl: https://api.example.com/oauth2/authorize
scopes:
read_access: read data
write_access: modify data
4.2. Расширение поставщика услуг
В подходе «сначала код» поставщик услуг может создать документацию OpenAPI на основе кода. Таким образом, схемы безопасности также должны быть обеспечены. Например, с Spring Boot, включая SpringFox, мы могли бы написать такой класс конфигурации:
@Configuration
public class OpenAPISecurityConfig {
@Autowired
void addSecurity(Docket docket) {
docket
.securitySchemes(of(authenticationScheme()))
.securityContexts(of(securityContext()));
}
private SecurityScheme authenticationScheme() {
return new OAuth2SchemeBuilder("implicit")
.name("my_oAuth_security_schema")
.authorizationUrl("https://api.example.com/oauth2/authorize")
.scopes(authorizationScopes())
.build();
}
private List<AuthorizationScope> authorizationScopes() {
return Arrays.asList(
new AuthorizationScope("read_access", "read data"),
new AuthorizationScope("write_access", "modify data")
);
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(readAccessAuth())
.operationSelector(operationContext ->
HttpMethod.GET.equals(operationContext.httpMethod())
)
.build();
}
private List<SecurityReference> readAccessAuth() {
AuthorizationScope[] authorizationScopes = new AuthorizationScope[] { authorizationScopes().get(0) };
return of(new SecurityReference("my_oAuth_security_schema", authorizationScopes));
}
}
Конечно, использование других технологий привело бы к другим реализациям. Но мы всегда должны помнить об OpenAPI, который должен быть сгенерирован.
4.3. Расширение потребителя услуг
Пользовательский интерфейс Swagger поддерживает схемы аутентификации OpenAPI по умолчанию — его не нужно настраивать. Тогда мы получим возможность аутентификации:
У других клиентов были бы другие решения. Например, есть модуль NPM для приложений Angular, который напрямую предоставляет OAuth2 и OpenID Connect (OIDC).
4.4. Ограничения пользовательского интерфейса Swagger
Пользовательский интерфейс Swagger поддерживает OpenID Connect Discovery, начиная с версии 3.38.0 (редактор Swagger, начиная с версии 3.14.8). К сожалению, SpringFox в текущей версии 3.0.0 упаковывает Swagger UI 3.26.2. Поэтому, если мы хотим включить пользовательский интерфейс Swagger более новой версии, нам нужно включить его непосредственно в наше приложение, используя ту же структуру каталогов, что и SpringFox, чтобы затмить файлы, упакованные SpringFox:
Вместо этого SpringDoc 1.6.1 не упаковывает пользовательский интерфейс Swagger, но объявляет транзитивную зависимость от пользовательского интерфейса Swagger 4.1.3 , поэтому у нас не будет проблем с SpringDoc.
5. Вывод
В этой статье мы указали на возможности тестирования REST-сервисов с пользовательским интерфейсом Swagger в случае использования Keycloak в качестве IAM. Лучшее решение — использовать такие стандарты, как OpenAPI, OAuth2 и OpenID Connect, которые все поддерживаются инструментами.
Как всегда, весь код доступен на GitHub .