1. 概述
本教程將介紹如何配置默認全局安全方案,並將其作為API的默認安全要求,使用springdoc-openapi庫在Spring MVC Web應用程序中實現。此外,我們還將討論如何覆蓋這些默認的安全要求。
OpenAPI規範允許我們為API定義一組安全方案。我們可以全局配置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 註解來啓動應用程序,並使用 SpringApplication 助手類來啓動它:
@SpringBootApplication
public class DefaultGlobalSecuritySchemeApplication {
public static void main(String[] args) {
SpringApplication.run(DefaultGlobalSecuritySchemeApplication.class, args);
}
}3. <em>springdoc-openapi</em> 基礎配置
一旦我們配置了 Spring MVC,我們來查看 API 語義信息。
我們將通過向 DefaultGlobalSecuritySchemeApplication 類添加 springdoc-openapi 註解,來定義默認的全局安全方案和 API 元數據。為了定義全局安全方案,我們將使用 @SecurityScheme 註解:
@SecurityScheme(type = SecuritySchemeType.APIKEY, name = "api_key", in = SecuritySchemeIn.HEADER)我們選擇了 APIKEY 安全方案類型,但我們也可以配置其他安全方案,例如 JWT。 在定義安全方案後,我們將添加元數據併為 API 建立默認的安全要求。 我們使用 @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. 控制器
現在我們已經配置了 Spring 框架和 springdoc-openapi 庫,讓我們在應用程序的基礎路徑中添加一個 REST 控制器。 要實現這一點,我們將使用 @RestController 和 @RequestMapping 註解:
@RestController
@RequestMapping("/")
public class DefaultGlobalSecuritySchemeOpenApiController {
...
}
之後,我們將定義兩個端點或 路徑。
第一個端點是 /login 端點。它將接收用户憑據並對用户進行身份驗證。如果身份驗證成功,端點將返回一個令牌。
API 的另一個端點是 /ping 端點,它需要 /login 方法生成的令牌。在執行請求之前,該方法會驗證令牌並檢查用户是否已授權。
總而言之,/login 端點對用户進行身份驗證並提供令牌。/ping 端點接收由/login 端點返回的令牌,並檢查其有效性以及用户是否可以執行操作。
4.1. login() 方法</h3
此方法將不具備任何安全要求。因此,我們需要覆蓋默認的安全配置要求
首先,我們需要告訴 Spring 這是一個 API 端點,因此我們將添加註解 @RequestMapping 以配置端點:
@RequestMapping(method = RequestMethod.POST, value = "/login", produces = { "application/json" }, consumes = { "application/json" })之後,我們需要為端點添加語義信息。我們將使用 @Operation 和 @SecurityRequirements 註解。 @Operation 將定義端點,而 @SecurityRequirements 將定義適用於該端點的特定安全要求:
@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()
以下是翻譯後的內容:
例如,以下是帶有狀態碼 200 的響應的 HTML 文檔:
最後,讓我們查看 login() 方法的簽名:
public ResponseEntity login(@Parameter(name = "LoginDto", description = "Login") @Valid @RequestBody(required = true) LoginDto loginDto) {
...
}如我們所見,API 請求的主體接收一個 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 端點的 HTML 文檔將是什麼樣子:
4.2. ping() 方法
在此階段,我們將定義 ping() 方法。 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) {
...
}
主要的區別在於 login() 方法和 ping() 方法的應用需求。 login() 方法將不具備任何安全需求,而 ping() 方法將在 API 級別定義安全要求。因此,HTML 文檔將僅顯示對 /ping 終點的鎖圖標。
5. REST API 文檔 URL
此時,我們已經準備好 Spring MVC Web 應用,並且可以啓動服務器:
mvn spring-boot:run -Dstart-class="com.baeldung.defaultglobalsecurityscheme.DefaultGlobalSecuritySchemeApplication"服務器準備就緒後,我們可以通過 http://localhost:8080/swagger-ui-custom.html 網址查看 HTML 文檔,如前例所示。
API 定義的 JSON 版本位於 http://localhost:8080/api-docs,YAML 版本位於 http://localhost:8080/api-docs.yaml。
這些輸出可用於使用 swagger-codegen-maven-plugin 構建不同語言的 API 客户端或服務器。
6. 結論
在本文中,我們學習瞭如何使用 springdoc-openapi 庫定義默認全局安全方案。我們還了解了如何將其應用於 API 的默認安全要求。此外,我們還學習瞭如何為特定端點更改默認安全要求。
我們還發現,可以使用來自 springdoc-openapi 的 JSON 和 YAML 輸出自動生成代碼。