在之前的分析中我們已經知道了Spring Security是由AuthenticationManager(ProviderManager)把認證請求分發給多個認證器。
在Spring Security中存在全局AuthenticationManager與局部AuthenticationManager兩種
我們先來看下面代碼:
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception{
//簡單定義一個基於內存的UserDetailsService實例 作為示范
InMemoryUserDetailsManager users=new InMemoryUserDetailsManager();
users.createUser(User.withUsername("javaboy").password("{noop}123456").roles("admin").build());
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.userDetailsService(users)
.csrf().disable();
}
}
此時我們雖然配置了UserDetailsService,但是我們發現使用 Spring Security生成的用戶 仍能登錄!
原因很簡單,因為此時我們注冊的是一個局部AuthenticationManager,系統仍會生成一個全局AuthenticationManager(AuthenticationConfiguration的getAuthenticationManager方法),全局AuthenticationManager會從Spring容器中尋找UserDetailsService實例,由於我們也沒有往容器中注入UserDetailsService實例,因此會使用系統提供的實例!
雖然在實際使用中對我們沒有太大的影響,因為Spring Security會先使用局部AuthenticationManager進行認證,再使用全局AuthenticationManager進行認證。但如果我們想要直接修改全局AuthenticationManager的話,有兩種思路:
(一)直接生成全局AuthenticationManager
(二)往Spring容器中注入UserDetailsService實例
先說第一種,生成全局AuthenticationManager只需要重寫configure(AuthenticationManagerBuilder auth)方法
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
UserDateService userDateService;
//注意是參數為AuthenticationManagerBuilder的configure方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDateService);
}
....
}
往Spring容器中注入UserDetailsService實例更簡單,只需要加一個@Bean注解即可!
需要注意的是,一旦我們重寫了configure(AuthenticationManagerBuilder auth)方法,則使用的UserDetailsService實例 則是 方法中注入的實例,此時容器中的UserDetailsService實例將不起作用!(AuthenticationConfiguration的getAuthenticationManager方法沒有被調用!)