上一篇文章分享了swagger(Java效率工具之Swagger2),有位读者留言想了解下,在生产环境如何去掉 swagger 包扫描,毕竟在生产环境我们会担心 API 的各类信息泄露导致安全问题。

那把这个需求再分解细化一下,我们来看最终想实现的,就是在生产环境中不要把 API 的信息暴露出去。

那针对这样的需求,我们一般会有哪些思路来处理呢?

我的思路大致有以下几点,欢迎留言一卢交流:

添加 Spring Security,对 swagger api 的请求进行权限检验。应用进行生产环境打包时,将 swagger 对应的内容移除根据不同的条件,在生产环境禁用 swagger, 其他环境启用

对于通过添加 Spring Security ,设置不同 request 的 Permit 和Deny 来进行控制。特殊打包,可以通过自定义 maven 插件的形式来实现。这两种我们先忽略。这里我们重点来说下第三种实现方式,「根据不同的条件,在生产环境禁用 swagger, 其他环境再启用」。这样就解决了我们的问题。


熟悉 Spring Boot 的读者可能都知道, Spring Boot 都是靠一系列 AutoConfiguration 工作的。我们每次新增的一个 Starter, 在启动的时候都会解析,判断其 AutoConfiguration是 否需要启用(Tomcat 是怎样处理 SpringBoot应用的?)。比如是否存在特定的Bean, 是否存在我写的 Class 等等。而这一切能够成立,其实是依赖 Spring 4.x 时新增的 Conditional。有了这个,才有了后面类似于 我们代码里的 if 条件判断。

所以,我们对于 swagger 是否启用,可以套用同样的思路,创建我们自己的 Condition, 再在不同的环境中使条件成立即可。


package com.example;
import org.springframework.context.annotation.Condition;import org.springframework.context.annotation.ConditionContext;import org.springframework.core.type.AnnotatedTypeMetadata;
/** * 公众号「Tomcat那些事儿」 * @author houshucheng */
public class OpenApiCondition implements Condition {    @Override    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {        String test = conditionContext.getEnvironment().getProperty("app-env");
       return test != null && test.equals("pro");    }}

然后再把这个 Condition 应用到 Swagger 的 Configuration 上。

package com.example.demo;
import com.example.OpenApiCondition;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Conditional;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;
import static springfox.documentation.builders.PathSelectors.regex;
/** * 公众号「Tomcat那些事儿」 * @author houshucheng */
@Configuration@EnableSwagger2@Conditional(OpenApiCondition.class)public class SwaggerConfig extends WebMvcConfigurationSupport {    @Bean    public Docket productApi() {        return new Docket(DocumentationType.SWAGGER_2)                .select() .apis(RequestHandlerSelectors.basePackage("com.example.web"))                .paths(regex("/product.*"))                .build();
   }  @Override    protected void addResourceHandlers(ResourceHandlerRegistry registry) {        registry.addResourceHandler("swagger-ui.html")                .addResourceLocations("classpath:/META-INF/resources/");
       registry.addResourceHandler("/webjars/**")                .addResourceLocations("classpath:/META-INF/resources/webjars/");    }}

之后启动的时候,对于需要用到 swagger 的环境,不需要做特殊处理,在启动后,直接请求 swagger-ui.html 即可。而对于不需要使用 swagger 的环境,只需要启动的时候,给程序传入参数:--app-env=pro 就可以了。由于不同的 Condition,可以控制 Swagger 的配置在不同环境下是否启用,来实现我们的需求。

有些时候,我们可以在阅读一些开源代码的时候,可以从中学习一些思路,应用到我们自己的项目,实现我们自己的需求。

对于这个问题,各位读者有哪些思路呢,欢迎留言一起交流