我正在使用 spring security 并实现了 UserDetailsService ,它完美地处理了我的用户登录过程。
问题是这样的: 是否有一种标准方法来检查每个请求的数据库中的用户状态,以便如果用户的帐户状态更改为“锁定”或他的角色在他仍然登录时发生更改,应用程序会阻止他继续工作。
这里的问题是,我的自定义 UserDetailsService 类中的“public UserDetails loadUserByUsername(String arg0)”仅在登录过程中调用,并且 userDetails 对象在登录过程执行后保留数据,并且 userDetails 信息不保存新鲜。
我可以通过一些解决方法来解决这个问题,例如从数据库获取用户对象并通过侦听器检查其状态。但我觉得 Spring Security 可能对这种情况有一个通用的解决方案。
请帮忙。谢谢。
基本思想是使用自定义的
SecurityContextRepository
,它会丢弃保存在http会话中的用户详细信息。
有关完整示例和工作项目,请查看我对类似问题的回答:Spring Security 在运行时注销用户
这个解决方案在 Spring-boot 3.x(和 Spring Security 6.x)上对我有用:
每当您使用
@EnableWebSecurity
时,您可能需要设置标准 UserDetailsService
bean...
所以你应该有这样的东西:
@Bean
public UserDetailsService userDetailsService() {
return username -> userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
您可以更改它以支持您的其他过滤器(在我的例子中,我为每个
Status
添加了一个 User entity
枚举,以在服务请求之前检查用户是否为 Status.Active
):
@Bean
public UserDetailsService userDetailsService() {
return username -> userRepository.findByUsernameAndStatus(username, Status.ACTIVE)
.orElseThrow(() -> new UsernameNotFoundException("User not found or not Active"));
}
不用说,JPA 在实现具有多个字段的
findBy
查询时非常方便,如我的 UserRepository
:
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
// Old method:
Optional<User> findByUsername(String username);
// New method:
Optional<User> findByUsernameAndStatus(String username, Status status);
}
最后一点:
由于我实现了自己的 custom
UserService
,所以我修改了 findBy
方法中的 loadUserByUsername
,如下所示:
@Service
public class UserService implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsernameAndStatus(username, Status.ACTIVE)
.orElseThrow(() -> new UsernameNotFoundException("User not found or not Active"));
return user;
}
...
...
祝你好运!