文章目录
- 前言
- 一、访问页面加权控制
- 1. 加权控制
- 2. 登录
- 二、生产环境如何屏蔽Knife4j、Swagger等Ui资源和接口
- 1. 基于Spring Boot框架提供的@Conditional条件控制相关@Bean的生效
- 2. 效果
- 三、聚合个性化配置
- 1. 用户服务
- 1.1 引入依赖
- 1.2 Knife4j配置类
- 1.3 控制器
- 2. 网关服务
- 2.1 排除用户服务
- 2.2 定义新用户服务路由
- 2.3 手动聚合分组
- 3. 效果展示
- 总结
前言
上一章已经完成了在网关层集成Knife4j,这里来做一些Knife4j常用功能的使用。
一、访问页面加权控制
上一章我们通过访问地址,就直接访问到了文档界面,这样做是不安全的,我们需要添加基本的权限控制,官方已经提供了此功能,我们完成配置并开启即可。
1. 加权控制
注意basic
的层级是在gateway
下面的
knife4j:
gateway:
# ① 第一个配置,开启gateway聚合组件
enabled: true
# ② 第二行配置,设置聚合模式采用discover服务发现的模式
strategy: discover
discover:
# ③ 第三行配置,开启discover模式
enabled: true
# ④ 第四行配置,聚合子服务全部为OpenAPI3规范的文档
version: openapi3
basic:
enable: true
# Basic认证用户名
username: admin
# Basic认证密码
password: admin
2. 登录
二、生产环境如何屏蔽Knife4j、Swagger等Ui资源和接口
这是个老生常谈的问题了,开发环境对外开放接口和静态ui资源,没有问题,但是生产为了保护应用程序安全,建议对接口拦截屏蔽
1. 基于Spring Boot框架提供的@Conditional条件控制相关@Bean的生效
Spring Boot配置起来很方便,简单地配置开关即可
knife4j:
gateway:
# ① 第一个配置,开启gateway聚合组件
enabled: false
# ② 第二行配置,设置聚合模式采用discover服务发现的模式
strategy: discover
discover:
# ③ 第三行配置,开启discover模式
enabled: true
# ④ 第四行配置,聚合子服务全部为OpenAPI3规范的文档
version: openapi3
basic:
enable: true
# Basic认证用户名
username: admin
# Basic认证密码
password: admin
2. 效果
可以看出,我们的配置已经生效,生产环境上线时,
修改配置knife4j.gateway.enabled: false
进行关闭,避免接口泄漏,造成安全问题
三、聚合个性化配置
这里我们对用户服务做个性化配置
1. 用户服务
1.1 引入依赖
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
1.2 Knife4j配置类
package org.example.user.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* Create by zjg on 2024/8/4
*/
@Configuration
public class Knife4jConfiguration {
@Value("${server.port}")
private int port;
/**
* 根据@Tag 上的排序,写入x-order
*
* @return the global open api customizer
*/
@Bean
public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
return openApi -> {
if (openApi.getTags()!=null){
openApi.getTags().forEach(tag -> {
Map<String,Object> map=new HashMap<>();
map.put("x-order", new Random().nextInt(0,100));
tag.setExtensions(map);
});
}
if(openApi.getPaths()!=null){
openApi.addExtension("x-test123","333");
openApi.getPaths().addExtension("x-abb",new Random().nextInt(1,100));
}
};
}
@Bean
public OpenAPI customOpenAPI() {
Info info = new Info();
Contact contact = new Contact();
contact.setName("zhangjg");
contact.setUrl("http://localhost:"+port);
contact.setEmail("zhangjg@gmail.com");
info.setContact(contact);
return new OpenAPI()
.info(info
.title("用户应用程序接口文档")
.version("1.0")
.description( "用户服务")
.termsOfService("http://doc.xiaominfo.com")
.license(new License().name("Apache 2.0")
.url("http://doc.xiaominfo.com")));
}
}
1.3 控制器
package org.example.user.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.example.common.model.Result;
import org.example.common.util.JwtUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Create by zjg on 2024/7/21
*/
@Tag(name = "用户模块")
@RestController
@RequestMapping("/user/")
public class UserController {
List<String> users = List.of("admin");
@Operation(summary = "用户是否存在")
@RequestMapping("exist")
public Boolean exist(@RequestParam("username") String username){
boolean exist=false;
if(users.contains(username)){
exist=true;
}
return exist;
}
@Operation(summary = "用户登录")
@RequestMapping("login")
public Result<String> login(@RequestParam("username") String username, @RequestParam("password") String password){
String message="用户名/密码不正确";
String admin="admin";
if(admin.equals(username)&&admin.equals(password)){
Map<String, Object> claims=new HashMap<>();
claims.put("username",username);
return new Result<>(HttpStatus.OK.value(), "请求成功",JwtUtils.create(claims));
}
return Result.error(HttpStatus.UNAUTHORIZED.value(), message);
}
}
2. 网关服务
现在是这么一个场景:用户服务太重要了,他们也要接入网关文档服务中,但是系统
server.servlet.context-path
配置还不能改,这么说大家可能不明白,直接看url区别吧
用户服务:http://localhost:9007/v3/api-docs
网关服务:http://localhost:9007/user/v3/api-docs
方案1
用户服务添加server.servlet.context-path=user
,但是如果你的系统已经有很多内容了,不建议改,它的影响范围是ALL
,会影响用户系统的所有请求。
方案2
用户服务添加接口/user/v3/api-docs
,接收到请求之后,获取本机http://localhost:9007/v3/api-docs
并将响应返回,相当于中转了一层
方案3
推荐
\color{#00FF00}{推荐}
推荐
其实我们的网关是很灵活的,这时候就需要网关层做动作适应它,先讲下思路:
- 排除的微服务
user-service
的knife4j
配置- 定义新的路由和新的断言规则,指向
user-service
- 手动配置
user-service
,聚合默认分组
2.1 排除用户服务
knife4j:
gateway:
# ① 第一个配置,开启gateway聚合组件
enabled: true
# ② 第二行配置,设置聚合模式采用discover服务发现的模式
strategy: discover
discover:
# ③ 第三行配置,开启discover模式
enabled: true
# ④ 第四行配置,聚合子服务全部为OpenAPI3规范的文档
version: openapi3
# 需要排除的微服务(eg:网关服务)
excluded-services:
- user-service
2.2 定义新用户服务路由
定义路由
user-service1
,并将请求http://localhost:9007/user/v3/api-docs
去掉一层前缀,真实请求为http://localhost:9007/v3/api-docs
,完美解决
spring:
cloud:
gateway:
httpclient:
connect-timeout: 1000
response-timeout: 5s
routes:
- id: provider-service
uri: lb://provider-service
predicates:
- Path=/provider/**
- BlackRemoteAddr=192.168.1.1/24,127.0.0.1,192.168.0.104
- id: consumer-service
uri: lb://consumer-service
predicates:
- Path=/consumer/**,/echo-rest/**,/echo-feign/**
filters:
- BlackList=/consumer/hello1,/consumer/hello2
metadata:
optionName: "OptionValue"
compositeObject:
name: "value"
iAmNumber: 1
connect-timeout: 200
response-timeout: 6000
- id: user-service
uri: lb://user-service
predicates:
- Path=/user/**
- id: user-service1
uri: lb://user-service
predicates:
- Path=/user-service/**
filters:
- StripPrefix=1
2.3 手动聚合分组
我们在
knife4j.gateway
下定义一套routes
匹配我们刚才的路由即可
knife4j:
gateway:
# ① 第一个配置,开启gateway聚合组件
enabled: true
# ② 第二行配置,设置聚合模式采用discover服务发现的模式
strategy: discover
discover:
# ③ 第三行配置,开启discover模式
enabled: true
# ④ 第四行配置,聚合子服务全部为OpenAPI3规范的文档
version: openapi3
# 需要排除的微服务(eg:网关服务)
excluded-services:
- user-service
# 子服务存在其他分组情况,聚合其他分组,只能手动配置
routes:
- name: 用户服务
# 子服务存在其他分组情况,聚合其他分组
url: /user-service/v3/api-docs?group=default
# 服务名称(Optional)
service-name: user-service
# 路由前缀
context-path: /
# 排序
order: 1
basic:
enable: true
# Basic认证用户名
username: admin
# Basic认证密码
password: admin
3. 效果展示
总结
回到顶部