012-从零搭建微服务-接口文档(二)

news/2024/11/29 22:48:31/

写在最前

如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

源码地址(后端):https://gitee.com/csps/mingyue

源码地址(前端):https://gitee.com/csps/mingyue-ui

文档地址:https://gitee.com/csps/mingyue/wikisapplication-common.yml

迁移配置

mingyue-auth => application-common.yml

将 Sa-Token 配置放入公共配置中,方便 components.security-schemes.apiKey.name= ${sa-token.token-name} 引用

# Sa-Token 配置
sa-token:# token名称 (同时也是 cookie 名称)token-name: Authorization# OAuth2.0 配置oauth2:is-code: trueis-implicit: trueis-password: trueis-client: true

优化 Swagger 配置

修改 SwaggerProperties

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;import java.util.Map;/*** SwaggerProperties** @author Strive* @date 2023/6/22 11:00*/
@Data
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {/*** 文档基本信息*/@NestedConfigurationPropertyprivate InfoProperties info = new InfoProperties();/*** 组件*/@NestedConfigurationPropertyprivate Components components = null;/*** 是否开启 swagger*/private Boolean enabled = true;/*** 网关*/private String gateway;/*** 服务转发配置*/private Map<String, String> services;/*** 文档的基础属性信息** @see io.swagger.v3.oas.models.info.Info*/@Datapublic static class InfoProperties {/*** 标题*/private String title = null;/*** 描述*/private String description = null;/*** 联系人信息*/@NestedConfigurationPropertyprivate Contact contact = null;/*** 许可证*/@NestedConfigurationPropertyprivate License license = null;/*** 版本*/private String version = null;}
}

修改 SwaggerAutoConfiguration

删除 securityScheme() 方法,修改 springOpenAPI()

import com.csp.mingyue.doc.support.SwaggerProperties;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.servers.Server;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.SpringDocConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.annotation.Bean;import java.util.ArrayList;
import java.util.List;
import java.util.Set;/*** Swagger 配置** @author Strive*/
@RequiredArgsConstructor
@AutoConfiguration(before = SpringDocConfiguration.class)
@ConditionalOnProperty(name = "swagger.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnMissingClass("org.springframework.cloud.gateway.config.GatewayAutoConfiguration")
public class SwaggerAutoConfiguration {private final SwaggerProperties swaggerProperties;private final ServiceInstance serviceInstance;@Beanpublic OpenAPI springOpenAPI() {OpenAPI openApi = new OpenAPI();// 文档基本信息SwaggerProperties.InfoProperties infoProperties = swaggerProperties.getInfo();Info info = convertInfo(infoProperties);openApi.info(info);// 鉴权方式配置openApi.components(swaggerProperties.getComponents());Set<String> keySet = swaggerProperties.getComponents().getSecuritySchemes().keySet();List<SecurityRequirement> list = new ArrayList<>();SecurityRequirement securityRequirement = new SecurityRequirement();keySet.forEach(securityRequirement::addList);list.add(securityRequirement);// servers 提供调用的接口地址前缀List<Server> serverList = new ArrayList<>();String path = swaggerProperties.getServices().get(serviceInstance.getServiceId());serverList.add(new Server().url(swaggerProperties.getGateway() + "/" + path));openApi.servers(serverList);return openApi;}/*** 装填文档的基础属性信息* @param infoProperties* @return io.swagger.v3.oas.models.info.Info*/private Info convertInfo(SwaggerProperties.InfoProperties infoProperties) {Info info = new Info();info.setTitle(infoProperties.getTitle());info.setDescription(infoProperties.getDescription());info.setContact(infoProperties.getContact());info.setLicense(infoProperties.getLicense());info.setVersion(infoProperties.getVersion());return info;}}

优化 getSysUsers 接口

通过 getSysUsers 接口使用 Swagger 注解小小实战一下

接口类增加 @Tag(name = “用户管理模块”)

@Tag(name = "用户管理模块")
public class SysUserController {

接口增加 @Tag(name = “用户管理模块”)

@Operation(summary = "获取所有用户信息")
public R<List<SysUser>> getSysUsers() {return R.ok(sysUserService.list());
}

响应类增加 @Schema(description = “用户实体类”)

@Schema(description = "用户实体类")
public class SysUser implements Serializable {

响应类字段增加 @Schema(description = “用户ID”)

@Schema(description = "用户ID")
private Long userId;

接口文档增加身份校验

升级 mingyue-gateway,支持接口文档增加身份校验

接口文档一般在开发环境使用,极其不推荐在生产使用,将接口文档暴露出来非常不安全。开发环境公司内部使用时可以直接使用,无须增加身份校验,如果暴露出去,还是增加一个身份校验比较好,安全些。

增加 SpringDocConfiguration 配置

import lombok.Data;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.SwaggerUiConfigParameters;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** SpringDoc Config** @author Strive* @date 2023-6-22*/
@Configuration(proxyBeanMethods = false)
public class SpringDocConfiguration {/*** 当 swagger.enabled = true 向 Bean 容器中注册改对象* @return*/@Bean@Lazy(false)@ConditionalOnProperty(name = "swagger.enabled", havingValue = "true", matchIfMissing = true)public List<GroupedOpenApi> apis(SwaggerUiConfigParameters swaggerUiConfigParameters,SwaggerDocProperties swaggerProperties) {List<GroupedOpenApi> groups = new ArrayList<>();// 读取配置服务,添加接口分组,以服务为纬度进行分组for (String value : swaggerProperties.getServices().values()) {swaggerUiConfigParameters.addGroup(value);}return groups;}@Data@Component@ConfigurationProperties("swagger")public class SwaggerDocProperties {/*** 添加接口文档的服务信息*/private Map<String, String> services;/*** 认证参数*/private SwaggerBasic basic = new SwaggerBasic();@Datapublic class SwaggerBasic {/*** 是否开启 basic 认证*/private Boolean enabled;/*** 用户名*/private String username;/*** 密码*/private String password;}}}

增加 SwaggerBasicGatewayFilter 过滤器

import com.csp.mingyue.gateway.config.SpringDocConfiguration;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.nio.charset.StandardCharsets;/*** Swagger 开启 Basic 认证** @author Strive* @date 2023/6/22*/
@Slf4j
@RequiredArgsConstructor
public class SwaggerBasicGatewayFilter implements GlobalFilter {private static final String API_URI = "/v3/api-docs";private static final String BASIC_PREFIX = "Basic ";private final SpringDocConfiguration.SwaggerDocProperties swaggerProperties;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();if (!request.getURI().getPath().contains(API_URI)) {return chain.filter(exchange);}if (hasAuth(exchange)) {return chain.filter(exchange);}else {ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);response.getHeaders().add(HttpHeaders.WWW_AUTHENTICATE, "Basic Realm=\"mingyue\"");return response.setComplete();}}/*** 简单的basic认证* @param exchange 上下文* @return 是否有权限*/private boolean hasAuth(ServerWebExchange exchange) {ServerHttpRequest request = exchange.getRequest();String auth = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);log.info("Basic认证信息为:{}", auth);if (!StringUtils.hasText(auth) || !auth.startsWith(BASIC_PREFIX)) {return Boolean.FALSE;}String username = swaggerProperties.getBasic().getUsername();String password = swaggerProperties.getBasic().getPassword();String encodeToString = Base64Utils.encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));return auth.equals(BASIC_PREFIX + encodeToString);}}

增加 GatewayConfiguration 配置

import com.csp.mingyue.gateway.filter.SwaggerBasicGatewayFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 网关配置** @author Strive*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
public class GatewayConfiguration {@Bean@ConditionalOnProperty(name = "swagger.basic.enabled")public SwaggerBasicGatewayFilter swaggerBasicGatewayFilter(SpringDocConfiguration.SwaggerDocProperties swaggerProperties) {return new SwaggerBasicGatewayFilter(swaggerProperties);}}

修改 Nacos mingyue-gateway.yml 配置

通过 enabled 控制是否开启接口文档密码校验,通过 usernamepassword 配置登录接口文档的用户名与密码

swagger:basic:# 是否开启接口文档密码校验enabled: trueusername: mingyuepassword: mingyue

启动测试

打开 swagger-ui: http://mingyue-gateway:9100/swagger-ui.html,会弹出登录框,输入 Nacos 中配置的用户名密码登录即可,查看是否配置成功!

image-20230623163859415

小结

Swagger 接口文档基础功能已经可以使用,但仍有很多很多需要做的地方,比如:

  1. Authorize 功能,也就是 Token 还未使用;
  2. 基于 Openapi 结构体接入第三方工具,如:ApifoxPostman等。为什么有 Swagger-UI ,要接入第三方工具?其实 Swagger-UI 很不好用,哈哈哈~;
  3. 导出接口文档,如PDF等文本格式;
  4. 。。。

山高路远,但仍要脚踏实地,收回来!下一篇我们先控制接口访问,必须携带有效 Token 才可以交互接口!


http://www.ppmy.cn/news/537184.html

相关文章

SVN教程

SVN使用教程总结 SVN简介&#xff1a; 为什么要使用SVN&#xff1f; 程序员在编写程序的过程中&#xff0c;每个程序员都会生成很多不同的版本&#xff0c;这就需要程序员有效的管理代码&#xff0c;在需要的时候可以迅速&#xff0c;准确取出相应的版本。 Subversion是什么&am…

【裸机开发】IRQ 中断服务函数(二)—— 全局中断初始化

实现了 IRQ 中断服务函数的汇编部分以后&#xff0c;接下来我们要使用C代码实现IRQ中断服务函数的具体逻辑&#xff0c;主要包含初始化和中断处理两部分。 全局中断初始化&#xff08;全局中断使能、IRQ中断使能&#xff09;具体中断处理逻辑实现 目录 一、全局中断初始化&am…

为什么要写这个带点玄幻气息的英语单词记忆博客

&#x1f31f;博主&#xff1a;命运之光 ☀️专栏&#xff1a;英之剑法&#x1f5e1; ❤️‍&#x1f525;专栏&#xff1a;英之试炼&#x1f525; ☀️博主的其他文章&#xff1a;点击进入博主的主页 &#x1f433; 开篇想说的话&#xff1a;开学就大三了&#xff0c;命运之光…

局域网聊天连接全集

布谷鸟2008 局域网聊天工具2008 5.01 下载- 华军软件园- 网络工具 ... 《布谷鸟2008 第二版》局域网聊天通讯办公软件&#xff0c;免费使用&#xff0c;无须注册。可实现局域网络间跨网段的聊天、群聊、和传送文件外&#xff0c;还包括&#xff1a;“日程安排”“通讯录”“个人…

公司禁用QQ之旅

公司要求上班时间禁止使用QQ等聊天工具&#xff0c;刚开始时想着直接把QQ使用的端口禁用掉&#xff0c;真正去实施时就发现问题来了&#xff0c;BT的腾讯&#xff0c;居然使用的是4000&#xff0c;8000&#xff0c;80端口&#xff0c;晕死&#xff0c;这些端口还真的关不得&…

公司禁用U盘的方法总结

U盘虽好&#xff0c;未必被公司管理者待见。因为员工乱插U盘会带来潜在病毒风险&#xff0c;最关键的是担心员工把重要文件通过优盘拷走了。公司禁用U盘是绕不过去的一道坎。 总结下常见的禁用U盘的方法&#xff1a; 方法一&#xff0c;物理封堵法&#xff1a; 把机箱所有US…

CoreMark 跑个分:OrangePi5 RK3588S

一、 Orange Pi 5 简介 Orange Pi 5 采用了瑞芯微 RK3588S 新一代八核 64 位处理器&#xff0c;具体为四核A76四核A55&#xff0c;采用了 8nm 工艺设计&#xff0c;主频最高可达 2.4GHz&#xff0c;集成 ARM Mali-G610 MP4 GPU&#xff0c;内嵌高性能 3D 和 2D 图像加速模块&am…

高校学生考勤系统

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括高校学生考勤系统的网络应用&#xff0c;在外国高校学生考勤系统已经是很普遍的方式&#xff0c;不过国内的高校学生考勤可能还处于起步阶段。高校学生考勤系统具有管理…