11.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
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() 所要的。
复制链接