When I run my app, I get the error I shown below that the dependencies of some of the beans in the application context form a cycle. Im not sure where exactly the problem is coming from. Still relatively new to spring boot/spring security so any pointers on my code on would be appreciated.
The dependencies of some of the beans in the application context form a cycle:
userController defined in file [/Users/jason/Desktop/Coding/Job-Application-Tracker/target/classes/com/example/jobapplicationtracker/controllers/UserController.class]
┌─────┐
| userServiceImpl defined in file [/Users/jason/Desktop/Coding/Job-Application-Tracker/target/classes/com/example/jobapplicationtracker/services/UserServiceImpl.class]
↑ ↓
| securityConfig defined in file [/Users/jason/Desktop/Coding/Job-Application-Tracker/target/classes/com/example/jobapplicationtracker/securities/SecurityConfig.class]
└─────┘
UserServiceImpl
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService, UserDetailsService {
@Autowired
private final UserRepository userRepository;
@Autowired
private final PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user == null){
log.error("User not found in the database");
throw new UsernameNotFoundException("User not found in the database");
} else {
log.info("User found in the database: {}", username);
}
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
user.getApplications().forEach(application -> authorities.add(new SimpleGrantedAuthority(application.getApplicationId().toString())));
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
}
@Override
public User getUser(String username) {
log.info("Fetching user {}", username);
return this.userRepository.findByUsername(username);
}
@Override
public List<User> getUsers() {
log.info("Fetching all users.");
return this.userRepository.findAll();
}
@Override
public User saveUser(User user) {
log.info("User {} is saved to the database", user);
user.setPassword( passwordEncoder.encode(user.getPassword()));
return this.userRepository.save(user);
}
}
SecurityConfig
@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;
private final AuthenticationConfiguration authenticationConfiguration;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception {
return auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()).and().build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests().anyRequest().permitAll();
http.addFilter(new CustomAuthenticationFilter(authenticationManagerBeans()));
return http.build();
}
@Bean
public AuthenticationManager authenticationManagerBeans() throws Exception
{
return authenticationConfiguration.getAuthenticationManager();
}
}
CodePudding user response:
Your issue relates to Prohibit circular references by default #27652, I'm not sure what was the motivation to prohibit circular dependencies by default, however the general recommendation now is "your code is poor - refactor it", on the other hand you may disable this feature via "spring.main.allow-circular-references=true".
In regard to your case:
SecurityConfig
"initialises"PasswordEncoder
and depends onUserDetailsService
UserDetailsService
depends onPasswordEncoder
so, it is clear that we got a cycle, and the "recommended solution" would be move PasswordEncoder
to another configuration class.