[英]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.