本文将介绍如何在 Spring MVC 应用中通过 springdoc-openapi 库配置默认全局安全方案,并将其作为 API 的默认安全要求。同时我们也会探讨如何覆盖这些默认安全要求。OpenAPI 规范允许我们为 API 定义一组安全方案,可以全局配置安全要求,也可以针对每个接口单独应用或移除。
2. 项目搭建
我们使用 Spring Boot 构建 Maven 项目,以下是项目搭建步骤。完成后将得到一个简单的 Web 应用。
2.1. 依赖管理
项目包含两个核心依赖:
spring-boot-starter-web:构建 Web 应用的基础依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.1.5</version> </dependency>
springdoc-openapi-ui:用于生成 HTML/JSON/YAML 格式的 API 文档
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.7.0</version> </dependency>
2.2. 应用入口
依赖配置完成后,定义应用入口类:
@SpringBootApplication
public class DefaultGlobalSecuritySchemeApplication {
public static void main(String[] args) {
SpringApplication.run(DefaultGlobalSecuritySchemeApplication.class, args);
}
}
3. springdoc-openapi 基础配置
配置好 Spring MVC 后,我们来定义 API 的语义信息。通过在入口类添加 springdoc-openapi 注解来配置全局安全方案和 API 元数据。
使用 @SecurityScheme
注解定义全局安全方案:
@SecurityScheme(type = SecuritySchemeType.APIKEY, name = "api_key", in = SecuritySchemeIn.HEADER)
这里选择了 APIKEY 安全方案类型,实际项目中也可以配置 JWT 等其他方案。接着使用 @OpenAPIDefinition
添加元数据并设置默认安全要求:
@OpenAPIDefinition(info = @Info(title = "Apply Default Global SecurityScheme in springdoc-openapi", version = "1.0.0"), security = { @SecurityRequirement(name = "api_key") })
info
属性定义 API 元数据security
属性设置默认全局安全要求
配置后,HTML 文档会显示元数据和全局安全按钮(适用于整个 API):
4. 控制器实现
现在添加一个 REST 控制器到上下文根路径。使用 @RestController
和 @RequestMapping
注解:
@RestController
@RequestMapping("/")
public class DefaultGlobalSecuritySchemeOpenApiController {
...
}
定义两个核心接口:
- **
/login
**:接收用户凭证进行认证,成功后返回令牌 - **
/ping
**:需要/login
生成的令牌,验证用户权限
4.1. 登录接口实现
此接口不需要安全验证,因此需要覆盖默认安全配置。
首先用 @RequestMapping
定义接口:
@RequestMapping(method = RequestMethod.POST, value = "/login", produces = { "application/json" }, consumes = { "application/json" })
然后添加语义信息:
@Operation(operationId = "login", responses = {
@ApiResponse(responseCode = "200", description = "api_key to be used in the secured-ping endpoint", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = TokenDto.class)) }),
@ApiResponse(responseCode = "401", description = "Unauthorized request", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ApplicationExceptionDto.class)) }) })
@SecurityRequirements()
@SecurityRequirements()
注解显式声明此接口不需要安全验证。状态码 200 的响应文档示例:
方法签名实现:
public ResponseEntity login(@Parameter(name = "LoginDto", description = "Login") @Valid @RequestBody(required = true) LoginDto loginDto) {
...
}
DTO 需要添加语义注解:
public class LoginDto {
private String user;
private String pass;
@Schema(name = "user", required = true)
public String getUser() {
return user;
}
@Schema(name = "pass", required = true)
public String getPass() {
return pass;
}
}
最终 /login
接口文档效果:
4.2. Ping 接口实现
此接口使用默认全局安全方案:
@Operation(operationId = "ping", responses = {
@ApiResponse(responseCode = "200", description = "Ping that needs an api_key attribute in the header", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = PingResponseDto.class), examples = { @ExampleObject(value = "{ pong: '2022-06-17T18:30:33.465+02:00' }") }) }),
@ApiResponse(responseCode = "401", description = "Unauthorized request", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ApplicationExceptionDto.class)) }),
@ApiResponse(responseCode = "403", description = "Forbidden request", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ApplicationExceptionDto.class)) }) })
@RequestMapping(method = RequestMethod.GET, value = "/ping", produces = { "application/json" })
public ResponseEntity ping(@RequestHeader(name = "api_key", required = false) String api_key) {
...
}
与登录接口的关键区别在于安全要求:
- 登录接口:无安全要求
- Ping 接口:继承 API 级别的安全配置
文档中会显示 /ping
接口带锁图标:
5. API 文档访问地址
启动应用服务器:
mvn spring-boot:run -Dstart-class="com.baeldung.defaultglobalsecurityscheme.DefaultGlobalSecuritySchemeApplication"
文档访问地址:
- HTML 文档:http://localhost:8080/swagger-ui-custom.html
- JSON 格式:http://localhost:8080/api-docs
- YAML 格式:http://localhost:8080/api-docs.yaml
这些输出可用于通过 swagger-codegen-maven-plugin 生成多语言客户端/服务端代码。
6. 总结
本文介绍了使用 springdoc-openapi 配置默认全局安全方案的核心技巧:
- 通过
@SecurityScheme
定义安全方案 - 使用
@OpenAPIDefinition
设置全局安全要求 - 用
@SecurityRequirements()
覆盖特定接口的安全配置
此外,我们还发现可以利用 springdoc-openapi 生成的 JSON/YAML 输出自动化代码生成。完整源码可在 GitHub 获取。