在Spring Security中可以同时存在多个过滤器链,一个WebSecurityConfigurerAdapter的实例就可以配置一条过滤器链。
我们来看如下一个案例:
@Configuration
public class SecurityConfig {
@Bean
UserDetailsService us(){
InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
users.createUser(User.withUsername("剑气近").password("{noop}123").roles("admin").build());
return users;
}
@Configuration
@Order(1)
static class SecurityConfig01 extends WebSecurityConfigurerAdapter{
@Override
protected void configure(HttpSecurity http) throws Exception {
InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
users.createUser(User.withUsername("chain1in").password("{noop}123").roles("admin").build());
http.antMatcher("/bar/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/mylogin.html")
.loginProcessingUrl("/bar/login")
.successHandler(((req, resp, auth) -> {
resp.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(auth);
resp.getWriter().write(s);
}))
.permitAll()
.and()
.csrf().disable()
.userDetailsService(users);
}
}
@Configuration
@Order(2)
static class SecurityConfig02 extends WebSecurityConfigurerAdapter{
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("chain2out").password("{noop}123").roles("admin");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
users.createUser(User.withUsername("chain2in").password("{noop}123").roles("admin").build());
http.antMatcher("/foo/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/mylogin.html")
.loginProcessingUrl("/foo/login")
.successHandler(((req, resp, auth) -> {
resp.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(auth);
resp.getWriter().write(s);
}))
.permitAll()
.and()
.csrf().disable()
.userDetailsService(users);
}
}
}
在SecurityConfig中分别定义两个静态内部类SecurityConfig01和SecurityConfig02,两个配置类都继承自WebSecurityConfigurerAdapter, 可以分别配置一条过滤器链。
先来看Security01,在Security01中,我们设置过滤器链的拦截规则是/bar/**,即如果请求路径是/bar/**格式的,则进入到Security01的过滤器链中进行处理。同时我们配置了局部 AuthenticationManager 对应的用户是 chain1in/123 ,由于没有重写 configure(AuthenticationManagerBuilder)方法,所以注册到 Spring 容器中的 UserDetailsService 将作为局部 AuthenticationManager的parent对应的用户,换句话说,如果登录的路径是/bar/login,那么升发者可以使用 chain1in/123和 剑气近/123两个用户进行登录。
再来看SecurityConfig02。在Security02中,我们设置过滤器链的拦截规则是/foo/**,即如果请求路径是/foo/**格式的,则进入到Secunty02的过滤器链中进行处理,同时我们配置了局部 AuthenticationManager 对应的用户是 chain2in/123 ,由于重写了 configure(Authentication ManagerBuilder)方法,在该方法中定义了局部AuthenticationManager的parent对应的用户,此时注册到Spring容器中的UserDetailsService实例对于/foo/**过滤器链不再生效。换句话说, 如果登录路径是/foo/login,开发者可以使用chain2in/123和 chain2out/123两个用户进行登录,而不可以使用 剑气近/123进行登录。
需要注意的是,如果配置了多个过滤器链,需要使用@Order注解来标记不同配置的优先级(即不同过滤器链的优先级),数字越大优先级越低,当请求到来时,会按照过滤器链的优先级从高往低,依次进行匹配。