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 单体架构

3、Spring Cloud 微服务架构

4、微服务聚合实战

4.1、Gateway 整合 Knife4j

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

1
2
3
4
5
6
knife4j:
enable: true # 开启增强配置
basic:
enable: true # 开启Basic身份认证
username: test # Basic认证用户名
password: 987789 # Basic认证密码

当 Gateway 与 Knife4j 整合在一起的时候,若业务模块配置了上述的 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 整合的项目。

手动方式

★展开代码★
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

全局参数设置 Access Token

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

knife4j-oauth2-7

6、参考文档