在 Springdoc 文档中配置身份认证,以访问需要认证的的端点

1、概览

Springdoc-OpenAPI 是一个为 Spring Boot 应用程序自动生成 API 文档的框架。它实现了 OpenAPI 3 规范,使用它,通过 UI 界面就可以与 API 进行交互,非常方便。

在本教程中,我们将学习如何使用 Spring Security 通过表单登录和 Basic Authentication 来认证 springdoc 中的端点访问。

2、项目设置

创建一个 Spring Boot Web 应用程序,该应用程序将通过 Spring Security 保护 API,并使用 Springdoc 生成文档。

2.1、依赖

首先添加 springdoc-openapi-ui,它整合了 Swagger-UI,用于提供 UI 界面:

http://localhost:8080/swagger-ui.html

其次,添加 springdoc-openapi-security,用于为 Spring Security 提供支持:

<dependency>
     <groupId>org.springdoc</groupId>
     <artifactId>springdoc-openapi-ui</artifactId>
     <version>1.6.13</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-security</artifactId>
    <version>1.6.13</version>
</dependency>

2.2、示例 API

创建一个示例 REST Controller,Springdoc 会为其生成文档。

此外,我们将通过 Swagger-UI 来演示与 FooController 中受保护(需要认证)的端点进行交互。

@RestController
@RequestMapping(value = "foos", produces = MediaType.APPLICATION_JSON_VALUE)
@OpenAPIDefinition(info = @Info(title = "Foos API", version = "v1"))
public class FooController {

    @GetMapping(value = "/{id}")
    public FooDTO findById(@PathVariable("id") final Long id) {
        return new FooDTO(randomAlphabetic(STRING_LENGTH));
    }

    @GetMapping
    public List<FooDTO> findAll() {
        return Lists.newArrayList(new FooDTO(randomAlphabetic(STRING_LENGTH)),
          new FooDTO(randomAlphabetic(STRING_LENGTH)), new FooDTO(randomAlphabetic(STRING_LENGTH)));
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public FooDTO create(@RequestBody final FooDTO fooDTO) {
        return fooDTO;
    }
}

2.3、用户凭证

我们使用 Spring Security 的内存认证(inMemoryAuthentication),来注册我们测试用户的凭证信息:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, PasswordEncoder passwordEncoder) throws Exception {
    auth.inMemoryAuthentication()
      .withUser("user")
      .password(passwordEncoder.encode("password"))
      .roles("USER");
}

3、基于表单的登录认证

让我们看看,如何使用基于表单的登录认证,来与受保护的端点进行交互。

3.1、Security 配置

定义 Security 配置,指定需要使用表单登录来进行认证的请求:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
      .antMatchers("/v3/api-docs/**",
        "/swagger-ui/**",
        "/swagger-ui.html").permitAll()
      .anyRequest().authenticated()
      .and()
      .formLogin()
      .defaultSuccessUrl("/foos");
    return http.build();
}

3.2、登录文档

默认情况下,框架提供的登录端点不会在文档中显示。需要修改其配置:

可以在官方 文档 中找到完整可用的配置属性。

springdoc.show-login-endpoint=true

随后,Springdoc 将检测已配置的 Spring Security 表单登录,并在 Swagger-UI 中生成文档。如下,它添加了一个 /login 端点,请求类型是 application/x-www-form-urlencoded,参数是 usernamepassword

swagger ui 中的登录端点

通过身份认证后,我们就可以调用 FooController 端点了。此外,由于 defaultSucccesfulUrl 配置,我们会从 /foos 端点获取成功登录的响应:

swagger ui 中登录成功的响应

3.3、注销文档

注销功能用于在 Swagger-UI 中进行用户切换。

Springdoc 并不像登录那样提供自动检测注销端点的方法。在这种情况下,我们需要定义一个 REST Controller,为 /logout 路径提供请求映射。不过,我们不需要进行任何实现,因为 Spring Security 会拦截并处理请求:

@RestController
public class LogoutController {

    @PostMapping("logout")
    public void logout() {}
}

添加 LogoutController 后,框架将会为其将生成文档并在 Swagger-UI 中提供注销功能:

Swagger-UI 中的注销端点

4、Basic Authentication

在请求 Basic Authentication (基础认证)端点时,不需要直接调用登录。

另外,OpenAPI 支持包括 Basic Authentication 在内的一系列标准 security scheme,我们可以据此配置 Springdoc。

4.1、Security Configuration

简单的安全配置,使用 Basic Authentication 保护端点:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeRequests()
      .antMatchers("/v3/api-docs/**",
        "/swagger-ui/**",
        "/swagger-ui.html").permitAll()
      .anyRequest().authenticated()
      .and()
      .httpBasic();
    return http.build();
}

4.2、Springdoc Security Scheme

要配置 OpenAPI Security Scheme,我们需要在配置类上使用 @SecurityScheme 注解进行配置:

@Configuration
@SecurityScheme(
  type = SecuritySchemeType.HTTP,
  name = "basicAuth",
  scheme = "basic")
public class SpringdocConfig {}

然后,还必须用 @SecurityRequirement(name = "basicAuth") 注解FooController。也可以在方法级别应用此注解,表示此认证方式只对该方法生效:

@RestController
@OpenAPIDefinition(info = @Info(title = "Foos API", version = "v1"))
@SecurityRequirement(name = "basicAuth")
@RequestMapping(value = "foos", produces = MediaType.APPLICATION_JSON_VALUE)
public class FooController {
    ...
}

此时,Swagger-UI 中会提供授权按钮:

Swagger-UI 中的授权按钮

然后,就可以在表单中提供用户凭证了:

Swagger-UI 中的表单登录

随后,当调用任何 FooController 中的端点时,包含了凭证信息的 Authorization Header 会被自动包含在请求中,如下图中生成的 curl 命令所示:

Swagger-UI curl 命令

5、总结

在本文中,我们学习了如何在 Springdoc 文档中配置身份认证,以访问受保护的端点。

我们介绍了基于表单和 Basic Authentication 的认证方式。


参考:https://www.baeldung.com/springdoc-openapi-form-login-and-basic-authentication