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() 所要的。

最后更新于