You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring自定义过滤器兼容Swagger UI并实现licenseKey校验的优化方案

优化SpringBoot中LicenseKey校验过滤器的实现思路

现有实现的问题点

  • 硬编码路径:Swagger相关路径写死在代码中,后续路径变更或新增白名单需修改代码重新部署
  • 校验逻辑缺失:仅获取licenseKey但未做有效性校验,未实现“必须携带有效licenseKey”的核心要求
  • 日志不规范:混用System.out.println和SLF4J日志,不利于线上问题排查
  • 拦截范围无控制:@Component注解导致过滤器对所有请求生效,未精准控制拦截目标
  • 异常处理缺失:licenseKey校验失败时,未向客户端返回标准错误响应

更优实现方案

方案一:基于Spring Security实现(推荐)

Spring Security提供成熟的请求拦截、权限校验机制,比自定义Filter更规范、易维护:

  1. 配置白名单路径,将Swagger相关路径纳入无需校验范围
  2. 自定义校验逻辑实现licenseKey有效性验证
  3. 通过SecurityFilterChain控制全局拦截规则

示例代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CustomUserDetailsService userDetailsService;

    public SecurityConfig(CustomUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // 根据业务场景决定是否关闭CSRF
            .authorizeHttpRequests(auth -> auth
                // 白名单:Swagger相关路径直接放行
                .requestMatchers("/app-name-service/swagger-ui/**", "/app-name-service/v3/api-docs/**").permitAll()
                // 其余所有请求需通过licenseKey校验
                .anyRequest().authenticated()
            )
            // 注入自定义licenseKey校验过滤器
            .addFilterBefore(licenseKeyAuthFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public Filter licenseKeyAuthFilter() {
        return (servletRequest, servletResponse, filterChain) -> {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;

            String licenseKey = userDetailsService.getLicenseKey(request);
            
            // 执行licenseKey有效性校验
            if (licenseKey == null || !userDetailsService.validateLicenseKey(licenseKey)) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType("application/json");
                response.getWriter().write("{\"code\":401,\"message\":\"缺失或无效的licenseKey\"}");
                return;
            }

            filterChain.doFilter(request, response);
        };
    }
}

方案二:改进自定义Filter实现

若不想引入Spring Security,可对原有Filter做针对性优化:

  1. 配置化白名单路径:通过@ConfigurationProperties将白名单路径配置到配置文件,避免硬编码

    @Component
    @ConfigurationProperties(prefix = "filter.license.whitelist")
    public class CustomURLFilter implements Filter {
        
        private List<String> paths = new ArrayList<>();
        
        // 省略getter/setter
        
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            
            String path = request.getRequestURI();
            
            // 判断请求路径是否在白名单内
            boolean isWhitelisted = paths.stream().anyMatch(path::startsWith);
            if (isWhitelisted) {
                filterChain.doFilter(request, response);
                return;
            }
            
            // 校验licenseKey有效性
            String licenseKey = userDetailsService.getLicenseKey(request);
            if (licenseKey == null || !userDetailsService.validateLicenseKey(licenseKey)) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType("application/json");
                response.getWriter().write("{\"code\":401,\"message\":\"缺失或无效的licenseKey\"}");
                return;
            }
            
            filterChain.doFilter(request, response);
        }
    }
    

    对应application.yml配置:

    filter:
      license:
        whitelist:
          - "/app-name-service/swagger-ui"
          - "/app-name-service/v3/api-docs"
    
  2. 精准控制拦截范围:使用@WebFilter指定拦截的URL模式,避免无差别拦截

    @WebFilter(urlPatterns = {"/app-name-service/**"}) // 仅拦截服务业务路径
    public class CustomURLFilter implements Filter {
        // 省略其他代码
    }
    

    同时在启动类添加@ServletComponentScan注解,开启Servlet组件扫描

  3. 规范日志与异常处理:统一使用SLF4J日志替代System.out.println;校验失败时返回标准HTTP错误响应,而非直接放行

额外优化建议

  • 将licenseKey校验逻辑封装为独立服务类,避免与Filter耦合
  • 若校验涉及数据库或远程调用,可对有效licenseKey做缓存,减少重复校验开销
  • Swagger后续配置授权时,可集成到统一的权限校验流程中,保持逻辑一致性

内容的提问来源于stack exchange,提问作者PythonLearner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:10:15