我有一个循环依赖错误的问题。当我在我的securityConfig类中定义UserDetailsService bean时抛出,但是如果我在我的authenticationConfig类中定义相同的bean,错误就会消失,我不知道为什么。这是代码
@Configuration
public class SecurityConfig {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private InitialAuthenticationFilter initialAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.csrf().disable()
.httpBasic().and()
.addFilterBefore(initialAuthenticationFilter, BasicAuthenticationFilter.class)
.addFilterAfter(jwtAuthenticationFilter,BasicAuthenticationFilter.class)
.authorizeHttpRequests().requestMatchers("/actuator/**").permitAll().and()
.authorizeHttpRequests().anyRequest().authenticated()
.and()
.build();
}
@Bean
public UserDetailsService userDetailsService(){
UserDetails user = User.builder()
.username("user")
.password("123")
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password("123")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
@Configuration
public class AuthenticationConfig {
@Autowired
private OtpAuthenticationProvider otpAuthenticationProvider;
@Autowired
private UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider;
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(usernamePasswordAuthenticationProvider).authenticationProvider(otpAuthenticationProvider);
return authenticationManagerBuilder.build();
}
}
@Component
public class InitialAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private AuthenticationManager manager;
@Value("${jwt.signing.key}")
private String signingKey;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { // do filtering
}
}
// and then i have some providers like this one
@Component
public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider{
@Autowired
private AuthenticationServerProxy proxy;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = String.valueOf(authentication.getCredentials());
proxy.sendAuth(username, password);
return new UsernamePasswordAuthenticationToken(username, password);
}
@Override
public boolean supports(Class<?> authentication) {
// TODO Auto-generated method stub
return UsernamePasswordAuthentication.class.isAssignableFrom(authentication);
}
}
这是日志:
Exception: org.springframework.beans.factory.UnsatisfiedDependencyException.
Message: Error creating bean with name 'securityConfig': Unsatisfied dependency expressed through field 'initialAuthenticationFilter':
Error creating bean with name 'initialAuthenticationFilter': Unsatisfied dependency expressed through field 'manager':
Error creating bean with name 'authManager' defined in class path resource [root/AuthenticationConfig.class]:
Unsatisfied dependency expressed through method 'authManager' parameter 0:
Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity'
defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]:
Failed to instantiate [org.springframework.security.config.annotation.web.builders.HttpSecurity]:
Factory method 'httpSecurity' threw exception with message: Error creating bean with name 'securityConfig':
Requested bean is currently in creation: Is there an unresolvable circular reference?
然后是这个图:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| securityConfig (field private root.filters.InitialAuthenticationFilter root.SecurityConfig.initialAuthenticationFilter)
↑ ↓
| initialAuthenticationFilter (field private org.springframework.security.authentication.AuthenticationManager root.filters.InitialAuthenticationFilter.manager)
↑ ↓
| authManager defined in class path resource [root/AuthenticationConfig.class]
↑ ↓
| org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity defined in class path resource [org/springframework/security/config/annotation/web/configuration/HttpSecurityConfiguration.class]
└─────┘
如果我移动UserDetailsService bean到另一个类,一切工作完美,但我试图了解在哪里是循环依赖来自。日志说authManager依赖于HttpSecurity,这是正确的,但是HttpSecurity依赖于securityConfig,我试着用调试器检查HttpSecurity bean,但找不到任何依赖
检查UserDetailsService
与HttpSecurity
没有任何直接关系。但是您必须使用UserDetailsService
来将角色定义为HttpSecurity
。您可以在Spring API HttpSecurity中找到相关信息。
循环依赖应该与AuthenticationManager
的HttpSecurity
相关。在旧版spring中,创建覆盖WebSecurityConfigurerAdapter
的AuthenticationManager
。代码类似于:
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
但是在最后的版本中,您可以使用filterChain
(在您的示例中是securityFilerChange
)来实例化AuthenticationManager
。bean可以是这样的:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(usernamePasswordAuthenticationProvider).authenticationProvider(otpAuthenticationProvider);
AuthenticationManager authenticationManager = authenticationManagerBuilder.build();
return http.csrf().disable()
.httpBasic().and().{...}
.anyRequest().authenticated()
.and()
.authenticationManager(authenticationManager).{...}
.build();
}
在这个实现中,你只有一个站点,你正在使用HttpSecurity和循环依赖错误应该消失。
关于如何升级WebSecurityConfigurerAdapter
,您可以在此链接中查看有关如何使用该AuthenticationManager
的更多信息。