Spring Security升级后filterChain Bean创建失败:AlreadyBuiltException问题
问题排查与解决:Spring Security升级后AlreadyBuiltException错误
问题原因
错误AlreadyBuiltException: This object has already been built的核心诱因:
- 在
filterChain方法中调用authenticationManager(http.getSharedObject(AuthenticationManagerBuilder.class))时,会触发AuthenticationManagerBuilder的build()方法,该操作会将当前HttpSecurity实例的构建状态标记为已完成。 - 后续执行
http.build()尝试构建SecurityFilterChain时,HttpSecurity已处于已构建状态,因此抛出异常。
解决方案
修改filterChain方法,直接注入Spring容器中已定义的AuthenticationManager Bean,而非通过HttpSecurity的共享对象动态创建。
修改后的完整配置类
package com.github.marceloasfilho.wallet.configuration; import com.github.marceloasfilho.wallet.filter.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import static org.springframework.security.config.Customizer.withDefaults; @Configuration @RequiredArgsConstructor public class SecurityConfiguration { @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("Marcelo") .passwordEncoder(bCryptPasswordEncoder()::encode) .password("password") .roles("USER") .build()); manager.createUser(User.withUsername("john") .passwordEncoder(bCryptPasswordEncoder()::encode) .password("1234") .roles("USER", "MANAGER") .build()); manager.createUser(User.withUsername("will") .passwordEncoder(bCryptPasswordEncoder()::encode) .password("1234") .roles("ADMIN") .build()); manager.createUser(User.withUsername("jim") .passwordEncoder(bCryptPasswordEncoder()::encode) .password("1234") .roles("ADMIN") .build()); manager.createUser(User.withUsername("arnold") .passwordEncoder(bCryptPasswordEncoder()::encode) .password("1234") .roles("SUPER_ADMIN") .build()); return manager; } // 修改点:注入AuthenticationManager Bean @Bean public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { http.csrf().disable() .authorizeHttpRequests() .antMatchers(HttpMethod.POST) .hasAnyRole("ADMIN", "SUPER_ADMIN") .antMatchers(HttpMethod.GET) .hasAnyRole("USER", "MANAGER") .and() .httpBasic(withDefaults()) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 使用注入的AuthenticationManager http.addFilter(new JwtAuthenticationFilter(authenticationManager)); return http.build(); } @Bean public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception { return auth .userDetailsService(userDetailsService()) .passwordEncoder(bCryptPasswordEncoder()) .and() .build(); } }
关键修改说明
- 在
filterChain方法参数中添加AuthenticationManager authenticationManager,让Spring自动注入已定义好的AuthenticationManager Bean。 - 将
http.addFilter(new JwtAuthenticationFilter(authenticationManager(http.getSharedObject(AuthenticationManagerBuilder.class))))替换为http.addFilter(new JwtAuthenticationFilter(authenticationManager)),直接使用注入的Bean。
此修改避免了在HttpSecurity构建流程中重复触发AuthenticationManager的build操作,彻底解决AlreadyBuiltException问题。
内容的提问来源于stack exchange,提问作者Marcelo Filho
相关产品推荐
相关产品推荐

