springSecurity认证管理器
SpringSecurity负责验证用户身份需要用到认证管理器(AuthenticationManager)。
认证管理器的接口很简单,只有一个方法,将用户名密码传入此认证器,如果不报错则为认证通过。
1 2 3 4
| public interface AuthenticationManager { Authentication authenticate(Authentication authentication) throws AuthenticationException; }
|
认证管理器
在springSecurity里,我们可以配置多个认证管理器,将多个认证管理器合并成一个ProviderManager
对外提供服务,只要有一个认证管理器认证通过,则表示通过,是一种责任链模式。
将多个authenticationProviders合并成一个的代码实现在这里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Override protected ProviderManager performBuild() throws Exception { ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager); if (eraseCredentials != null) { providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials); } if (eventPublisher != null) { providerManager.setAuthenticationEventPublisher(eventPublisher); } providerManager = postProcess(providerManager); return providerManager; }
|
配置认证管理器
配置的方式有两种,一种是重写下面的方法,配置好userDetailService
和 passwoedEncoder
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(new UserDetailsService() { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return null; } }).passwordEncoder(new PasswordEncoder() { @Override public String encode(CharSequence rawPassword) { return null; }
@Override public boolean matches(CharSequence rawPassword, String encodedPassword) { return false; } });
}
|
上面的代码则会自动配置一个DaoAuthentication
。
另一种方式是将userDetailService
和 passwordEncoder
配置成spring的bean,框架就能自动查找到。
具体实现请查看在@EnableGlobalAuthentication
注解是如何做的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| @Bean public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) { return new InitializeUserDetailsBeanManagerConfigurer(context); }
@Autowired(required = false) public void setGlobalAuthenticationConfigurers( List<GlobalAuthenticationConfigurerAdapter> configurers) { configurers.sort(AnnotationAwareOrderComparator.INSTANCE); this.globalAuthConfigurers = configurers; }
class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter { @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { if (auth.isConfigured()) { return; } UserDetailsService userDetailsService = getBeanOrNull( UserDetailsService.class); if (userDetailsService == null) { return; } PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class); UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class); DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailsService); if (passwordEncoder != null) { provider.setPasswordEncoder(passwordEncoder); } if (passwordManager != null) { provider.setUserDetailsPasswordService(passwordManager); } provider.afterPropertiesSet();
auth.authenticationProvider(provider); }
|
上面两种配置方式都是可以的,本人更推荐第一种方式。一方面代码几种在一个配置文件里,比较方便查找,一方面如果想配置多个HttpSecurity
,每个有独立的UserDetailService
也更方便。
框架对两种配置方式如何选择的
查看代码
1
| org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager
|
通过configure
方法重写,如果没重写则为自动配置,重写了就是手动配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| protected AuthenticationManager authenticationManager() throws Exception { if (!authenticationManagerInitialized) { configure(localConfigureAuthenticationBldr); if (disableLocalConfigureAuthenticationBldr) { authenticationManager = authenticationConfiguration .getAuthenticationManager(); } else { authenticationManager = localConfigureAuthenticationBldr.build(); } authenticationManagerInitialized = true; } return authenticationManager; }
protected void configure(AuthenticationManagerBuilder auth) throws Exception { this.disableLocalConfigureAuthenticationBldr = true; }
|