[英]Bean Cycle Spring Security
我正在開發一個 Spring 引導 web 應用程序。 問題出在登錄場景中,並且 ima 堆積在循環中。 寫道依賴關系是相互關聯的,我無法弄清楚究竟是如何以及為什么
描述:
application context中的一些bean的依賴關系形成了一個循環:
┌─────┐
| webSecurityConfig (field boot.service.UserDetailsServiceImpl boot.configs.WebSecurityConfig.userDetailsService)
↑ ↓
| userDetailsServiceImpl (field org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder boot.service.UserDetailsServiceImpl.bCryptPasswordEncoder)
└─────┘
我該如何解決這個問題,伙計們? 我的課程:
@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());
}
}
幫我弄清楚,我的腦袋已經壞了,谷歌也幫不上忙
如果您從 Spring 閱讀UserDetailsService
ervice 接口的 javadoc - 實現的責任應該是“加載用戶數據”。
您實施的問題在於您打算將其用於更多目的,即“節省用戶”。 要保存用戶,您的UserDetailsService
ervice 還依賴於WebSecurityConfig
中提供的PasswordEncoder
bean,但是為了提供一個UserDetailsService
ervice 是必需的 - 這就是那個循環。
這表明設計中存在錯誤,應該以某種方式進行重構。
打破這個循環的最簡單方法是允許延遲注入PasswordEncoder
,方法是在UserDetailsServiceImpl
erviceImpl class 中用@Lazy
注釋它——但我不建議這樣做。 它會讓你擺脫這種情況,但糟糕的設計選擇不會得到糾正。
我建議將loadUserByUsername
實現以外的所有邏輯從UserDetailsServiceImpl
移到其他一些@Service
(即UserService
)中。 - 這樣你就會尊重 Spring 的UserDetailsService
接口中定義的契約,並且你的UserDetailsServiceImpl
將不會依賴於PasswordEncoder
bean - 因此你的循環依賴將被刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.