I'm developing a Spring boot web application. The problem is in the login scenario, and ima stacked in loop. Writes that the dependencies are interconnected, and I can't figure out exactly how and why
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| webSecurityConfig (field boot.service.UserDetailsServiceImpl boot.configs.WebSecurityConfig.userDetailsService)
↑ ↓
| userDetailsServiceImpl (field org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder boot.service.UserDetailsServiceImpl.bCryptPasswordEncoder)
└─────┘
How can i resolve this, guys? My classes:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@PersistenceContext
private EntityManager em;
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return user;
}
public User findUserById(Long userId) {
Optional<User> userFromDb = userRepository.findById(userId);
return userFromDb.orElse(new User());
}
public List<User> allUsers() {
return userRepository.findAll();
}
public boolean saveUser(User user) {
User userFromDB = userRepository.findByUsername(user.getUsername());
if (userFromDB != null) {
return false;
}
user.setRoles(Collections.singleton(new Role(1L, "ROLE_User")));
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRepository.save(user);
return true;
}
public boolean deleteUser(Long userId) {
if (userRepository.findById(userId).isPresent()) {
userRepository.deleteById(userId);
return true;
}
return false;
}
public List<User> usergtList(Long idMin) {
return em.createQuery("SELECT u from User u WHERE u.id > :paramId", User.class)
.setParameter("paramId", idMin).getResultList();
}
}
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/registration").not().fullyAuthenticated()
.antMatchers(("/admin/**")).hasRole("ADMIN")
.antMatchers("/", "/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/");
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
Help me figure it out, I've already broken my whole head, Google does not help
If you read javadoc of the UserDetailsService
interface from Spring - a responsibility of the implementation should be "loading of User data".
The problem with your implementation is that you intended it for much more than that, ie "saving user". To save a User, your UserDetailsService
is also dependant on the PasswordEncoder
bean which is supplied in the WebSecurityConfig
, but in order to be suppplied a UserDetailsService
is needed - this is that cycle.
This indicates an error in design and should be refactored somehow.
The easiest way to break that cycle is to allow a PasswordEncoder
to be injected lazily, by annotating it with @Lazy
in your UserDetailsServiceImpl
class - but I don't recommend doing it. It will get you out of this situation, but the poor design choice will not be corrected.
I would recommend moving all logic other than loadUserByUsername
implementation away from the UserDetailsServiceImpl
into some other @Service
(ie UserService
). - that way you will respect the contract defined in the Spring's UserDetailsService
interface, and your UserDetailsServiceImpl
will not be dependant on the PasswordEncoder
bean - thus your cyclic dependency will be removed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.