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

如何基于@Profile为Spring Security添加不同的过滤器?

我来帮你搞定这个基于环境动态注册过滤器的需求,刚好之前做过类似场景,给你梳理下清晰的实现步骤:

实现方案:基于配置文件动态注册不同的PreAuthenticated过滤器

1. 先定义两个过滤器实现类

分别对应开发环境和非开发环境的逻辑,都继承AbstractPreAuthenticatedProcessingFilter:

// 开发环境专属过滤器:从请求头获取USER_ID
public class DevPreAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
    public DevPreAuthFilter() {
        // 先设置基础的认证管理器,后续可根据需求替换为自定义实现
        setAuthenticationManager(new PreAuthenticatedAuthenticationManager());
    }

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        // 从请求头提取USER_ID作为认证主体
        return request.getHeader("USER_ID");
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        // 开发环境凭证可以留空或设为固定值,这里用"dev-local"标记
        return "dev-local";
    }
}

// 非开发环境专属过滤器:从请求头获取JWT
public class JwtPreAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
    public JwtPreAuthFilter() {
        setAuthenticationManager(new PreAuthenticatedAuthenticationManager());
    }

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        // 从Authorization头提取Bearer格式的JWT
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }
        return null;
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        // JWT场景下凭证可与主体一致,直接返回提取到的Token
        return getPreAuthenticatedPrincipal(request);
    }
}

2. 用Profile控制Bean的实例化

通过@Profile注解,让Spring只在对应环境下创建指定的过滤器Bean:

@Configuration
public class FilterBeanConfig {

    // 仅当"development"配置文件激活时,创建开发环境过滤器Bean
    @Bean
    @Profile("development")
    public DevPreAuthFilter devPreAuthFilter() {
        return new DevPreAuthFilter();
    }

    // 当"development"配置文件未激活时,创建JWT过滤器Bean
    @Bean
    @Profile("!development")
    public JwtPreAuthFilter jwtPreAuthFilter() {
        return new JwtPreAuthFilter();
    }
}

3. 基于Bean存在性编程式注册过滤器

这里提供两种常用的注册方式,你可以根据场景选择:

方式一:注册为全局Servlet过滤器

用@ConditionalOnBean检测Bean是否存在,自动注册到Servlet容器:

@Configuration
public class FilterRegistrationConfig {

    // 仅当DevPreAuthFilter Bean存在时(即开发环境),注册该过滤器
    @Bean
    @ConditionalOnBean(DevPreAuthFilter.class)
    public FilterRegistrationBean<DevPreAuthFilter> registerDevFilter(DevPreAuthFilter filter) {
        FilterRegistrationBean<DevPreAuthFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns("/*"); // 匹配所有请求
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 确保优先执行
        return registrationBean;
    }

    // 仅当JwtPreAuthFilter Bean存在时(非开发环境),注册该过滤器
    @Bean
    @ConditionalOnBean(JwtPreAuthFilter.class)
    public FilterRegistrationBean<JwtPreAuthFilter> registerJwtFilter(JwtPreAuthFilter filter) {
        FilterRegistrationBean<JwtPreAuthFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }
}

方式二:集成到Spring Security过滤器链

如果是作为认证过滤器使用,更推荐这种方式,直接把过滤器加入Security的认证流程:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    // 用required=false实现按需注入,不存在的Bean会被设为null
    @Autowired(required = false)
    private DevPreAuthFilter devPreAuthFilter;

    @Autowired(required = false)
    private JwtPreAuthFilter jwtPreAuthFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            // 根据存在的Bean动态添加对应的前置过滤器
            .addFilterBefore(getActivePreAuthFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    private AbstractPreAuthenticatedProcessingFilter getActivePreAuthFilter() {
        if (devPreAuthFilter != null) {
            return devPreAuthFilter;
        } else if (jwtPreAuthFilter != null) {
            return jwtPreAuthFilter;
        }
        // 兜底处理:如果两个Bean都不存在,抛出异常提示
        throw new IllegalStateException("No valid pre-authentication filter bean found");
    }
}

核心逻辑说明

  • @Profile精准控制不同环境下的Bean实例化,确保同一时间只有一个过滤器Bean存在
  • @ConditionalOnBean或@Autowired(required=false)用来检测Bean的存在性,实现基于Bean本身存在状态的动态注册
  • 过滤器的AuthenticationManager可以根据实际业务替换,比如JWT场景下可以改成能解析Token并生成认证信息的自定义管理器

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:48:29