如何基于条件跳过Spring Security FilterChain,切换SSO与基础认证
解决Spring Security根据配置跳过SSO FilterChain的问题
方案一:条件化注册SSO FilterChain Bean
最直接的方式是通过配置属性控制是否创建这个高优先级的SSO FilterChain。当SSO未启用时,该Bean不会被注册,请求会自动流向优先级更低的基础认证FilterChain。
修改后的代码:
@Bean @Order(10) @ConditionalOnProperty(name = "sso.enabled", havingValue = "true") // 替换为你的配置属性键 protected SecurityFilterChain samlFilterChain(final HttpSecurity http) throws Exception { OpenSamlAuthenticationProvider authenticationProvider = new OpenSamlAuthenticationProvider(); authenticationProvider.setResponseAuthenticationConverter(groupsConverter()); http.csrf().disable() .authorizeHttpRequests(authorize -> authorize .antMatchers("/**") .permitAll() .anyRequest().authenticated() ) .saml2Login(saml2 -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) ) .saml2Login() .successHandler(successRedirectHandler()) .failureHandler(failureRedirectHandler()) .and() .saml2Logout(Customizer.withDefaults()); return http.build(); }
- 当配置属性
sso.enabled为false时,这个@Order(10)的FilterChain不会被加载,请求会直接进入后续的基础认证FilterChain(确保基础认证FilterChain的Order值大于10,比如100)。
方案二:在当前FilterChain中直接传递请求(强制跳过)
如果无法通过条件化注册Bean,可在FilterChain中添加自定义过滤器,当SSO未启用时直接将请求传递给下一个FilterChain,不做任何拦截处理。
修改后的代码:
@Bean @Order(10) protected SecurityFilterChain samlFilterChain(final HttpSecurity http) throws Exception { if (!isSsoEnabled) { // 添加自定义过滤器,直接转发请求到下一个FilterChain http.addFilterBefore(new OncePerRequestFilter() { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { filterChain.doFilter(request, response); } }, UsernamePasswordAuthenticationFilter.class); // 配置所有请求直接放行,避免当前链拦截 http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll()); return http.build(); } // SSO启用时的原有配置 OpenSamlAuthenticationProvider authenticationProvider = new OpenSamlAuthenticationProvider(); authenticationProvider.setResponseAuthenticationConverter(groupsConverter()); http.csrf().disable() .authorizeHttpRequests(authorize -> authorize .antMatchers("/**") .permitAll() .anyRequest().authenticated() ) .saml2Login(saml2 -> saml2 .authenticationManager(new ProviderManager(authenticationProvider)) ) .saml2Login() .successHandler(successRedirectHandler()) .failureHandler(failureRedirectHandler()) .and() .saml2Logout(Customizer.withDefaults()); return http.build(); }
- 核心逻辑是通过自定义
OncePerRequestFilter调用filterChain.doFilter(),实现你想要的请求传递效果;同时配置authorizeHttpRequests允许所有请求,确保当前链不会对请求做任何拦截处理。
为什么原代码的http.anonymous()无效?
http.anonymous()只是允许匿名用户访问请求,但会让当前FilterChain完成处理流程,不会将请求传递给下一个FilterChain。如果后续有基础认证的FilterChain,会因为当前链已经放行请求而无法触发。
内容的提问来源于stack exchange,提问作者tarmogoyf
相关产品推荐
相关产品推荐

