12.5.2 配置响应式用户信息服务
在扩展 WebSecurityConfigureAdapter
时,可以通过覆写 configure()
方法来声明 web 安全规则。通常通过定义 UserDetails
对象,并使用另一个 configure()
方法配置用户身份验证逻辑。重温一下,下面的代码是通过 UserDetails
的匿名实现类,使用注入的 UserRepository 对象,按用户名查找用户:
@Autowired
UserRepository userRepo;
@Override
protected void
configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.userDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = userRepo.findByUsername(username)
if (user == null) {
throw new UsernameNotFoundException(
username " + not found")
}
return user.toUserDetails();
}
});
}
在这个非响应式配置中,您覆写查找用户所需的唯一方法 UserDetailsService.loadUserByUsername()
。在这个方法中,您使用给定的 UserRepository
,按给定用户名查找用户。如果找不到,就抛出 UsernameNotFoundException
。如果找到了,就使用 toUserDetails()
返回 UserDetails
结果对象。
在响应式安全配置中,不覆写 configure()
方法,而是声明一个 ReactiveUserDetailsService
类型的 bean。ReactiveUserDetailsService
是与 UserDetailsService
等价的响应式服务。和 UserDetailsService
类似,ReactiveUserDetailsService
只需要实现一个方法。更明确地说,findByUsername()
方法要返回一个 Mono<UserDetails>
,而不是原始的 UserDetails
对象。
在下面的示例中,ReactiveUserDetailsService
声明为使用给定的 UserRepository
,它被认为是一个响应式的 Spring Data Repository
(我们将在下一章中详细讨论):
@Service
@Bean
public ReactiveUserDetailsService userDetailsService(
UserRepository userRepo) {
return new ReactiveUserDetailsService() {
@Override
public Mono<UserDetails> findByUsername(String username) {
return userRepo.findByUsername(username)
.map(user -> {
return user.toUserDetails();
});
}
};
}
这里,根据需要返回 Mono<UserDetails>
,但是 UserRepository.findByUsername()
方法返回一个 Mono<User>
。因为它是 Mono,您可以进行链式操作。例如通过 map()
操作把 Mono<User>
映射成 Mono<UserDetails>
。
在本例中,map()
操作使用 lambda 表达式的形式,通过 User 对象上的 toUserDetails()
方法,发布成 Mono。把 User 对象转换成 UserDetails 对象。因此,.map()
操作返回一个 Mono<UserDetails>
,这正是 ReactiveUserDetailsService.findByUsername()
所要的。