Spring Cloud Gateway + Swagger 3.0 实战:5分钟搞定微服务文档聚合与权限控制
当微服务数量超过两位数时,开发团队往往会面临这样的困境:每个服务都有独立的Swagger文档入口,测试人员需要记住十几个不同的URL,新入职的同事要花半天时间才能找全所有接口文档。更棘手的是,这些暴露在公网的文档可能包含敏感接口信息。上周我们团队就遇到了一次未授权访问事故——某爬虫抓取了内网Swagger页面,导致部分接口逻辑泄露。
本文将演示如何用Spring Cloud Gateway快速聚合所有微服务的Swagger 3.0文档,并通过网关层实现统一的账号密码验证。与网上大多数教程不同,我们采用最新Spring Boot 2.7+和Swagger 3.0组合,并特别优化了以下场景:
- 已有微服务无需修改代码
- 网关配置不超过20行核心代码
- 从零开始到完整运行只需5分钟
- 支持动态路由变更自动同步文档
1. 环境准备与依赖配置
确保所有微服务已升级到Spring Boot 2.7+,网关服务添加以下关键依赖:
<!-- Gateway必须的starter --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- Swagger 3.0核心库 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> <!-- WebFlux安全支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>版本适配注意点:
- Spring Boot 2.7.x对应Spring Cloud 2021.x
- Swagger 3.0的
/v3/api-docs端点与2.0不兼容 - WebFlux安全配置与传统Servlet环境有差异
2. 动态文档聚合实现
创建SwaggerResourceProvider实现类,自动发现所有注册微服务的文档端点:
@Primary @Component @RequiredArgsConstructor public class GatewaySwaggerProvider implements SwaggerResourcesProvider { private final RouteLocator routeLocator; private static final String API_DOCS_PATH = "/v3/api-docs"; @Override public List<SwaggerResource> get() { return routeLocator.getRoutes() .filter(route -> route.getUri().getHost() != null) .map(route -> { SwaggerResource resource = new SwaggerResource(); resource.setName(route.getId()); resource.setUrl("/" + route.getId() + API_DOCS_PATH); return resource; }) .collectList() .block(); } }这段代码实现了:
- 从网关路由表自动获取所有服务ID
- 为每个服务生成标准化的Swagger资源路径
- 动态响应路由变化(新增/删除服务无需重启)
3. 安全防护配置
在application.yml中配置基础认证信息:
swagger: security: username: docadmin password: $2a$10$N9qo8uLOickgx2ZMRZoMy.MQDqShq6HSiS4uY5pAG6PhJHAW7vJGW # bcrypt加密密码通过WebFluxSecurity配置访问控制:
@Bean public SecurityWebFilterChain swaggerSecurityChain(ServerHttpSecurity http) { return http .authorizeExchange(exchanges -> exchanges .pathMatchers( "/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**" ).authenticated() .anyExchange().permitAll() ) .formLogin(withDefaults()) .httpBasic(withDefaults()) .csrf(ServerHttpSecurity.CsrfSpec::disable) .build(); } @Bean public MapReactiveUserDetailsService userDetailsService() { UserDetails user = User.builder() .username(securityProperties.getUsername()) .password(securityProperties.getPassword()) .roles("DOC_VIEWER") .build(); return new MapReactiveUserDetailsService(user); }安全增强建议:
- 生产环境建议集成OAuth2/OIDC
- 通过IP白名单限制访问范围
- 启用HTTPS防止密码嗅探
4. 网关路由优化策略
在路由配置中需要特别注意Swagger相关路径的透传:
spring: cloud: gateway: routes: - id: service-order uri: lb://service-order predicates: - Path=/order/** filters: - StripPrefix=1 # 特殊处理Swagger路径 - id: service-order-docs uri: lb://service-order predicates: - Path=/service-order/v3/api-docs filters: - RewritePath=/service-order/(?<segment>.*), /$\{segment}这种配置方式实现了:
- 业务接口与文档接口分离路由
- 保留原始服务文档路径结构
- 支持负载均衡调用
5. 前端界面定制技巧
默认Swagger UI可能需要进行企业级定制,在网关层可以通过静态资源覆盖实现:
- 创建
resources/static/swagger-ui/目录 - 从
springfox-swagger-ui包复制原始文件 - 修改
index.html中的关键配置:
<script> window.onload = function() { const config = { urls: [ {url: "/v3/api-docs/service-order", name: "订单服务"}, {url: "/v3/api-docs/service-payment", name: "支付服务"} ], dom_id: "#swagger-ui", deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: "StandaloneLayout" }; window.ui = SwaggerUIBundle(config); }; </script>定制化效果包括:
- 中文界面显示
- 服务分类展示
- 企业LOGO植入
- 自定义颜色主题
访问http://gateway:8080/swagger-ui/index.html即可看到聚合后的文档中心,首次访问会弹出HTTP Basic认证对话框。实际项目中我们还添加了访问日志记录、文档版本快照等功能,这些扩展点都可以在网关层统一实现。