Knife4j 基础使用教程

1、前言

1.1、Knife4j 简介

Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的增强解决方案,前身是 swagger-bootstrap-ui,致力于 springfox-swagger 的增强 UI 实现。knife4j 为了契合微服务的架构发展,由于原来 swagger-bootstrap-ui 采用的是后端 Java 代码 + 前端 UI 混合打包的方式,在微服务架构下显的很臃肿,因此项目正式更名为 knife4j,更名后主要专注的方面如下:

  • 后端 Java 代码以及前端 UI 模块进行了分离,在微服务架构下使用更加灵活
  • 提供专注于 Swagger 的增强解决方案,不同于只是单纯增强前端 UI 部分

1.2、Knife4j 模块

模块名称说明
knife4j 为 Java MVC 框架集成 Swagger 的增强解决方案
knife4j-admin 云端 Swagger 接口文档注册管理中心,集成 gateway 网关对任意微服务文档进行组合集成
knife4j-extensionchrome 浏览器的增强 swagger 接口文档 ui, 快速渲染 swagger 资源
knife4j-service 为 swagger 服务的一系列接口服务程序
knife4j-frontknife4j-spring-ui 的纯前端静态版本,用于集成非 Java 语言使用
swagger-bootstrap-uiknife4j 的前身,最后发布版本是 1.9.6

1.3、使用 Knife4j 的业务场景

若不使用 knife4j 的增强功能,相当于纯粹换了一个 Swagger 的前端界面,这种情况是最简单的,原项目结构下无需作任何变更,可以直接引用 swagger-bootstrap-ui 的最后一个版本 1.9.6 或者使用 knife4j-spring-ui

1
2
3
4
5
6
<!-- 旧版本引用 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>`swagger-bootstrap-ui`</artifactId>
<version>1.9.6</version>
</dependency>
1
2
3
4
5
6
<!-- 新版本引用 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
<version>${lastVersion}</version>
</dependency>

若在 Spring Boot 项目单体架构使用增强功能,knife4j 提供了 starter 供开发者快速使用,该包会引用 knife4j 提供的所有资源,包括前端 UI 和后端的 Jar 包

1
2
3
4
5
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>

若在 Spring Cloud 的微服务架构下,每个微服务其实并不需要引入前端的 UI 资源,因此在每个微服务的 Spring Boot 项目里,只需引入 knife4j 提供的微服务 starter 即可

1
2
3
4
5
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>

最后在 Spring Cloud 的网关聚合文档服务(如 Zuul、Gateway)里,再把前端的 UI 资源引入

1
2
3
4
5
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>

不管是 knife4j 还是 swagger-bootstrap-ui,对外提供的访问地址依然是 http://ip:port/doc.html;同时 swagger-bootstrap-ui 使用的是传统的 Javascript 技术,即 jQuery + DOM 操作,打包后的源码并没有压缩处理,而 knife4j 的前端则采用 Vue。

2、Spring 单体架构

2.1、基于 Maven Bom 方式使用

2.2、Spring MVC 框架集成 Knife4j

2.3、Spring Boot 框架集成 Knife4j


3、Spring Cloud 微服务架构

3.1、Spring Cloud Zuul 集成 Knife4j

3.2、Spring Cloud Gateway 集成 Knife4j


4、微服务聚合实战

4.1、Eureka 聚合 Knife4j

4.2、Nacos 聚合 Knife4j

4.3、Gateway 聚合 Knife4j

Gateway 聚合 Knife4j 后,若需要对业务模块的的 API 文档接口 /v2/api-doc 添加 Basic 身份认证,则只需在对应的业务模块下的 YML 配置文件里添加以下内容即可:

1
2
3
4
5
6
7
8
knife4j:
cors: true
enable: true # 是否开启增强配置
basic:
username: test # Basic认证用户名
password: 987789 # Basic认证密码
enable: true # 开启Basic身份认证
production: false # 是否屏蔽所有Swagger的相关资源,默认是false

若业务模块配置了上述的 Basic 身份认证后,此时访问 Gateway 的聚合文档服务的 Web 界面,会弹出用户名和密码的输入框(如下图)

gateway-knife4j-1

5、Knife4j 整合 OAuth2.0

Knife4j 整合 OAuth2.0 的 Java 代码配置如下,关键在于创建 Docket 对象时,指定 OAuth2.0 的授权模式,包括简化模式 (implicit)、授权码模式 (authorization_code)、密码模式 (password)、客户端模式 (client_credentials)。值得一提的是,无论项目采用 Spring 单体架构还是 Spring Cloud 微服务架构,下面介绍的 Knife4j + OAuth2.0 的整合方式都适用,包括 Gateway + Knife4j + OAuth2.0 整合的项目。


下面提到的 @EnableBeanValidator 注解类的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(BeanValidatorPluginsConfiguration.class)
public @interface EnableBeanValidator {

}

手动方式

★展开代码★
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.Collections;
import java.util.List;

@Configuration
@EnableBeanValidator
@EnableSwagger2WebMvc
public class SwaggerConfiguration {

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.shop"))
.paths(PathSelectors.any())
.build()
// 整合OAuth2.0
.securitySchemes(Collections.singletonList(apiKey()))
.securityContexts(Collections.singletonList(securityContext()));
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Knife4j 接口文档")
.description("业务接口 API 文档.")
.termsOfServiceUrl("")
.version("v1.0.0")
.build();
}

private ApiKey apiKey() {
return new ApiKey("Bearer", "Authorization", "header");
}

/**
* Swagger2 认证的安全上下文
*
* @return
*/
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.any())
.build();
}

/**
* 认证方式
*
* @return
*/
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("web", "access_token");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Collections.singletonList(new SecurityReference("Bearer", authorizationScopes));
}

}


最终呈现的界面如下,填写提前获取到的 Access Token 即可,如下图所示:

knife4j-oauth2-1

刷新业务接口的调试界面,就会看到参数 Authorization 值已经更新了,如下图所示:

knife4j-oauth2-2

客户端模式

★展开代码★
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import com.google.common.collect.Lists;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableBeanValidator
@EnableSwagger2WebMvc
public class SwaggerConfiguration {

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemes())
.apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Knife4j 接口文档")
.description("业务接口 API 文档.")
.termsOfServiceUrl("")
.version("v1.0.0")
.build();
}

/**
* Swagger2 认证的安全上下文
*
* @return
*/
private List<SecurityContext> securityContexts() {
List<AuthorizationScope> scopes = new ArrayList<>();
SecurityReference securityReference = new SecurityReference("oauth2", scopes.toArray(new AuthorizationScope[]{}));
SecurityContext securityContext = new SecurityContext(Lists.newArrayList(securityReference), PathSelectors.ant("/**"));
return Lists.newArrayList(securityContext);
}

/**
* OAuth2.0 的认证方式
*
* @return
*/
private List<SecurityScheme> securitySchemes() {
// 使用客户端模式(client_credentials)
List<GrantType> grantTypes = new ArrayList<>();
String clientTokenUrl = "http://127.0.0.1:18010/oauth/token";
ClientCredentialsGrant clientCredentialsGrant = new ClientCredentialsGrant(clientTokenUrl);
grantTypes.add(clientCredentialsGrant);
OAuth oAuth = new OAuthBuilder().name("oauth2").grantTypes(grantTypes).build();
return Lists.newArrayList(oAuth);
}

}


输入 clientId 以及 clientSecret,然后点击 Authorize 按钮进行授权即可,如下图所示:

knife4j-oauth2-3

密码模式

★展开代码★
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import com.google.common.collect.Lists;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableBeanValidator
@EnableSwagger2WebMvc
public class SwaggerConfiguration {

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemes())
.apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Knife4j 接口文档")
.description("业务接口 API 文档.")
.termsOfServiceUrl("")
.version("v1.0.0")
.build();
}

/**
* Swagger2 认证的安全上下文
*
* @return
*/
private List<SecurityContext> securityContexts() {
List<AuthorizationScope> scopes = new ArrayList<>();
SecurityReference securityReference = new SecurityReference("oauth2", scopes.toArray(new AuthorizationScope[]{}));
SecurityContext securityContext = new SecurityContext(Lists.newArrayList(securityReference), PathSelectors.ant("/**"));
return Lists.newArrayList(securityContext);
}

/**
* OAuth2.0 的认证方式
*
* @return
*/
private List<SecurityScheme> securitySchemes() {
// 使用密码模式(password)
List<GrantType> grantTypes = new ArrayList<>();
String passwordTokenUrl = "http://127.0.0.1:18010/oauth/token";
ResourceOwnerPasswordCredentialsGrant resourceOwnerPasswordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(passwordTokenUrl);
grantTypes.add(resourceOwnerPasswordCredentialsGrant);
OAuth oAuth = new OAuthBuilder().name("oauth2").grantTypes(grantTypes).build();
return Lists.newArrayList(oAuth);
}

}


输入 usernamepasswordclientId 以及 clientSecret,然后点击 Authorize 按钮进行授权即可,如下图所示:

knife4j-oauth2-4

授权模式

★展开代码★
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import com.google.common.collect.Lists;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableBeanValidator
@EnableSwagger2WebMvc
public class SwaggerConfiguration {

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemes())
.apiInfo(apiInfo());
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Knife4j 接口文档")
.description("业务接口 API 文档.")
.termsOfServiceUrl("")
.version("v1.0.0")
.build();
}

/**
* Swagger2 认证的安全上下文
*
* @return
*/
private List<SecurityContext> securityContexts() {
List<AuthorizationScope> scopes = new ArrayList<>();
SecurityReference securityReference = new SecurityReference("oauth2", scopes.toArray(new AuthorizationScope[]{}));
SecurityContext securityContext = new SecurityContext(Lists.newArrayList(securityReference), PathSelectors.ant("/**"));
return Lists.newArrayList(securityContext);
}

/**
* OAuth2.0 的认证方式
*
* @return
*/
private List<SecurityScheme> securitySchemes() {
// 使用授权码模式(authorization_code)
List<GrantType> grantTypes = new ArrayList<>();
TokenRequestEndpoint tokenRequestEndpoint = new TokenRequestEndpoint("http://127.0.0.1:18010/oauth/authorize", "client1", "secert1");
TokenEndpoint tokenEndpoint = new TokenEndpoint("http://127.0.0.1:18010/oauth/token", "access_token");
AuthorizationCodeGrant authorizationCodeGrant = new AuthorizationCodeGrant(tokenRequestEndpoint, tokenEndpoint);
grantTypes.add(authorizationCodeGrant);
OAuth oAuth = new OAuthBuilder().name("oauth2").grantTypes(grantTypes).build();
return Lists.newArrayList(oAuth);
}

}


输入 clientIdclientSecret,然后点击 Authorize 按钮,最终跳转授权界面,如下图所示:

knife4j-oauth2-5


选择进行授权,授权完成后就可以直接调试接口了,如下图所示(该图与上述代码不相关,来源于网络):

knife4j-oauth2-6

简化模式(待补充)

6、全局参数设置 Oauth 的 Token

除了上面介绍的 Knife4j 自动获取 Access Token 之外,还可以通过 Knife4j 全局参数设置的功能来手动添加 Access Token,可以省去整合 OAuth2.0 的 Java 代码,这里 Access Token 的格式必须是以 bearer + 空格 作为前缀

knife4j-oauth2-7

7、参考文档