配置多个数据源

多个数据源是指在同一个系统中,用户数据来自不同的表,在认证时,如果第一张表没有查找到用户,那就去第二张表中查询,依次类推。

看了前面的分析,要实现这个需求就很容易了。认证要经过 AuthenticationProvider,每一个 AuthenticationProvider 中都配置了一个 UserDetailsService,而不同的 UserDetailsService 则可以代表不同的数据源。所以我们只需要手动配置多个 AuthenticationProvider,并为不同的 AuthenticationProvider 提供不同的 UserDetailsService 即可。

为了方便起见,这里通过 InMemoryUserDetailsManager 来提供 UserDetailsService 实例,在实际开发中,只需要将 UserDetailsService 换成自定义的即可,具体配置如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    @Primary
    UserDetailsService us1() {
        return new InMemoryUserDetailsManager(User.builder()
                .username("javaboy").password("{noop}123").roles("admin").build());
    }

    @Bean
    UserDetailsService us2() {
        return new InMemoryUserDetailsManager(User.builder()
                .username("sang").password("{noop}123").roles("user").build());
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean()
            throws Exception {
        DaoAuthenticationProvider dao1 = new DaoAuthenticationProvider();
        dao1.setUserDetailsService(us1());
        DaoAuthenticationProvider dao2 = new DaoAuthenticationProvider();
        dao2.setUserDetailsService(us2());
        ProviderManager manager = new ProviderManager(dao1, dao2);
        return manager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
        //省略
    }
}

首先定义了两个 UserDetailsService 实例,不同实例中存储了不同的用户;然后重写 authenticationManagerBean 方法,在该方法中,定义了两个 DaoAuthenticationProvider 实例并分别设置了不同的 UserDetailsService;最后构建 ProviderManager 实例并传入两个 DaoAuthenticationProvider。当系统进行身份认证操作时,就会遍历 ProviderManager 中不同的 DaoAuthenticationProvider,进而调用到不同的数据源。

在本书的配套案例中,笔者提供了一个基于 MyBatis 配置多数据源的案例,读者可以参考。