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

Spring Boot中为多DispatcherServlet配置差异化安全上下文的方法

解决Spring Boot多DispatcherServlet下的Security隔离问题

这个问题的核心在于Spring Security的默认FilterChainProxy Filter是全局生效的——不管请求由哪个DispatcherServlet处理,它都会拦截所有路径的请求。所以即使你的第二个Servlet上下文没注册SecurityConfig,请求还是会被Security Filter拦下。下面给你两种可行的解决方案:

方案一:通过WebSecurity忽略非API路径

直接在SecurityConfig中配置,让Spring Security完全忽略所有非/api开头的请求,这些请求不会经过任何Security Filter链,彻底禁用安全机制:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final BCryptPasswordEncoder passwordEncoder;
    private final DataSource dataSource;

    @Autowired
    public SecurityConfig(BCryptPasswordEncoder passwordEncoder, DataSource dataSource) {
        this.passwordEncoder = passwordEncoder;
        this.dataSource = dataSource;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
            .usersByUsernameQuery(USERS_BY_USERNAME_QUERY)
            .authoritiesByUsernameQuery(AUTHORITIES_BY_USERNAME_QUERY)
            .dataSource(dataSource)
            .passwordEncoder(passwordEncoder);
    }

    // 新增:配置WebSecurity忽略非API路径
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 正则匹配所有不以/api开头的请求,直接跳过Security处理
        web.ignoring().regexMatchers("^(?!/api).*");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated().and()
            .formLogin()
            .loginPage("/api/login")
            .usernameParameter("username")
            .passwordParameter("password")
            .and()
            .httpBasic().and()
            .csrf().disable();
    }
}

这种方式简单直接,适合你的场景:/api/*路径的请求会走完整的Security校验,其他路径(由secondServlet处理)完全不受Security影响。

方案二:自定义Security Filter的映射路径

通过覆盖Spring Boot自动注册的FilterChainProxy的FilterRegistrationBean,让Security Filter只作用于/api/*路径:

@SpringBootApplication(exclude = {DispatcherServletAutoConfiguration.class})
public class Application{
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    // ... 已有的FirstServletRegistration和SecondServletRegistration方法 ...

    // 新增:自定义Security Filter的映射路径
    @Bean
    public FilterRegistrationBean<FilterChainProxy> securityFilterChainProxy(FilterChainProxy filterChainProxy) {
        FilterRegistrationBean<FilterChainProxy> registrationBean = new FilterRegistrationBean<>(filterChainProxy);
        // 只让Security Filter拦截/api/*路径的请求
        registrationBean.addUrlPatterns("/api/*");
        // 设置最高优先级,确保Security Filter在其他Filter之前执行
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }
}

这种方式更灵活,如果你后续需要调整Security的作用路径,直接修改addUrlPatterns的参数即可。

额外注意点

  • 你的Servlet注册顺序是正确的:firstServlet映射/api/*(更具体的路径),secondServlet映射/*,Servlet容器会优先匹配更具体的路径,所以/api开头的请求会由firstServlet处理,其他请求由secondServlet处理,这部分无需修改。
  • 确保SecurityConfig只在firstServlet的上下文里注册(你已经做到了,FirstWebConfig的上下文注册了它,而SecondWebConfig没有),避免secondServlet的上下文被Security配置污染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:59:38