项目场景:

项目中使用swagger来自动生成接口文档,为了防止接口文档地址在外网被访问,需要对swagger的静态资源链接以及动态接口请求根据host属性做一些处理,使得外网域名不能访问接口文档地址。一个容易想到的办法就是通过Spring的Interceptor来实现,在preHandle方法中对swagger的请求路径做拦截。


问题描述

SwaggerInterceptor可以拦截到/swagger-ui.html请求,但是始终无法拦截/v2/api-docs接口,用户还是可以通过直接访 /v2/api-docs获取所有接口的json格式信息。

@Configuration
public class CorsConfig implements WebMvcConfigurer {


    @Bean
    public AuthInterceptor authInterceptor() {
        return new AuthInterceptor();
    }
    

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor())
                // 拦截所有请求
                .addPathPatterns("/**");
    }
}

原因分析:

首先,检查拦截器的配置,发现AuthInterceptor配置是拦截全部请求addPathPatterns(“/**”),并且可以拦截到/swagger-ui.html,确认不是拦截器全局配置的问题。

解决方案:

既然自定的HanderMapping初始化未绑定拦截器,导致拦截器失效,那我们换一种思路,通过ResponseBodyAdvice配合@ControllerAdvice注解,在请求响应体返回之前,校验请求URL,若为外网请求的Swagger路径,进行拦截。

@RestControllerAdvice
public class SwaggerAdvice implements ResponseBodyAdvice {

    private static final List<String> EXCLUDE_URL = Arrays.asList("/v2/api-docs");

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        String url = serverHttpRequest.getURI().getHost() + serverHttpRequest.getURI().getPath();
        if (EXCLUDE_URL.stream().anyMatch(item -> url.contains(item))) {
            serverHttpResponse.setStatusCode(HttpStatus.FORBIDDEN);
            throw new BusinessException("鉴权失败,该行为未授权,暂无权访问");
        }
        return o;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }
}

结果:

至此,可以做到拦截/v2/api-docs接口的外网请求
在这里插入图片描述

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐