创建名为'springSecurityConfig'的bean时出错:所请求的bean目前正在创建中:是否存在无法解决的循环引用?
创建名为'springSecurityConfig'的bean时出错:所请求的bean目前正在创建中:是否存在无法解决的循环引用?
我在使用BCryptPasswordEncoder对内存中的用户密码进行编码时遇到了错误。以下是我的SpringSecurityConfig文件:\n
SpringSecurityConfig类
\n
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .anyRequest() .authenticated() .and() .httpBasic(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin") .password(passwordEncoder().encode("password")) .roles("USER"); } @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
\n我该如何正确编码密码,以避免出现bean创建错误?
错误的原因是由于循环依赖导致的,解决方法是创建一个单独的配置类并将PasswordEncoder方法移动到该类中。示例代码如下:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class PasswordEncoderConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
然后将SpringSecurityConfig类修改如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin") .password(passwordEncoder.encode("password")) .roles("USER"); } }
通过将PasswordEncoder方法移动到单独的配置类中,避免了循环依赖的问题,并将该配置类通过@Autowired注入到SpringSecurityConfig中使用。这样就解决了循环依赖导致的问题。
问题出现的原因是由于bean之间存在循环依赖关系,导致创建bean时发生错误。具体来说,SpringSecurityConfig
类中的UserDetailsService
bean依赖于PasswordEncoder
bean,而PasswordEncoder
bean又依赖于SpringSecurityConfig
类。
解决这个问题的方法是通过将UserDetailsService
bean的依赖关系移动到SpringSecurityConfig
类的构造函数中。这样一来,SpringSecurityConfig
类的创建不再依赖于PasswordEncoder
bean,从而解决了循环依赖的问题。
修改后的代码如下所示:
public class SpringSecurityConfig { private final PasswordEncoder encoder; public SpringSecurityConfig(PasswordEncoder encoder) { this.encoder = encoder; } public SecurityFilterChain appSecurity(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .anyRequest() .authenticated() .and() .httpBasic(); return http.build(); } public UserDetailsService userDetailsService() { User admin = User.withUsername("admin") .password(encoder.encode("password")) .roles("USER").build(); return new InMemoryUserDetailsManager(admin); } public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
通过将PasswordEncoder
作为构造函数的参数传入SpringSecurityConfig
类中,解决了循环依赖问题。
更多详情可以参考Spring Security的官方文档:https://docs.spring.io/spring-security/reference/5.7.0-M3/servlet/authentication/passwords/in-memory.html。