1. 概述

在这个教程中,我们将专注于测试一个使用Keycloak进行身份验证和授权的安全REST服务,并通过Swagger UI进行访问。

2. 挑战

像其他Web资源一样,REST API通常会受到保护。因此,服务消费者(如Swagger UI)不仅需要处理HTTP调用,还需要向服务提供者提供身份验证信息。

Keycloak是一个IAM服务器,它允许在服务提供者的实现之外进行身份验证和授权。这是架构的一部分,如下图所示:

我们可以看到,服务提供者和服务消费者都需要与Keycloak服务器通信。首先,我们需要安装一个Keycloak服务器并将其集成到Spring Boot应用中,作为REST服务提供者。然后,我们需要扩展Swagger UI。

3. 集成Swagger UI

要在Spring Boot和Swagger UI之间集成,只需将库添加到项目依赖列表中(无需额外配置):

<dependency>
     <groupId>org.springdoc</groupId>
     <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
     <version>2.5.0</version>
</dependency>

4. 使用标准

对于供应商特定的代码扩展Swagger UI,只有在特殊情况下才有意义。因此,我们应该优先选择供应商无关的标准。接下来的章节将描述如何实现这一点。

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和SpringDoc的情况下,我们可以编写这样一个配置类:

@Configuration
public class OpenAPISecurityConfig {

    @Value("${keycloak.auth-server-url}")
    String authServerUrl;
    @Value("${keycloak.realm}")
    String realm;

    private static final String OAUTH_SCHEME_NAME = "my_oAuth_security_schema";

    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI().components(new Components()
            .addSecuritySchemes(OAUTH_SCHEME_NAME, createOAuthScheme()))
            .addSecurityItem(new SecurityRequirement().addList(OAUTH_SCHEME_NAME))
            .info(new Info().title("Todos Management Service")
                .description("A service providing todos.")
                .version("1.0"));
    }

    private SecurityScheme createOAuthScheme() {
        OAuthFlows flows = createOAuthFlows();
        return new SecurityScheme().type(SecurityScheme.Type.OAUTH2)
            .flows(flows);
    }

    private OAuthFlows createOAuthFlows() {
        OAuthFlow flow = createAuthorizationCodeFlow();
        return new OAuthFlows().implicit(flow);
    }

    private OAuthFlow createAuthorizationCodeFlow() {
        return new OAuthFlow()
            .authorizationUrl(authServerUrl + "/realms/" + realm + "/protocol/openid-connect/auth")
            .scopes(new Scopes().addString("read_access", "read data")
                .addString("write_access", "modify data"));
    }

}

当然,使用其他技术会有不同的实现。但我们始终应该意识到必须生成的OpenAPI。

4.3. 扩展服务消费者

Swagger UI默认支持OpenAPI认证方案,无需自定义。我们将能够通过它进行身份验证:

其他客户端可能有不同的解决方案。例如,有一个NPM模块可以为Angular应用程序提供简单易用的OAuth2和OpenID Connect (OIDC)支持。

5. 通过Swagger UI测试端点

按照这篇文章提供的配置,您应该已经配置了一个用户,可以登录应用。为了使用Swagger UI,还需要配置客户端(login-app)并启用"隐式流身份验证方法":

还需要关联应用程序范围(读取和写入),首先在客户端范围会话中创建这些范围:

然后将它们添加到应用程序启用范围的列表中:

现在,您可以在地址http://localhost:8081/swagger-ui/index.html上访问[Swagger UI应用](/swagger-2-documentation-for-spring-rest-api),并使用正确的范围进行身份验证:

最后,我们可以通过Swagger访问控制器端点:

6. 总结

在这篇文章中,我们指出了在使用Keycloak作为IAM时,通过Swagger UI测试REST服务的可能性。最佳解决方案是使用OpenAPI、OAuth2和OpenID Connect等标准,这些工具都支持这些标准。

如往常一样,所有代码可在GitHub上获取。