定义多个过滤器链
在 Spring Security 中可以同时存在多个过滤器链,一个 WebSecurityConfigurerAdapter 的实例就可以配置一条过滤器链。我们来看如下一个案例:
@Configuration
public class SecurityConfig {
@Bean
UserDetailsService us() {
InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
users.createUser(User.withUsername("javaboy").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("bar").password("{noop}123").roles("admin").build());
http.antMatcher("/bar/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.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("javagirl")
.password("{noop}123")
.roles("admin");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
InMemoryUserDetailsManager users = new InMemoryUserDetailsManager();
users.createUser(User.withUsername("foo").password("{noop}123").roles("admin").build());
http.antMatcher("/foo/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.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 对应的用户是 bar/123,由于没有重写 configure(AuthenticationManagerBuilder) 方法,所以注册到 Spring容器中的 UserDetailsService 将作为局部 AuthenticationManager 的 parent 对应的用户。换句话说,如果登录的路径是 /bar/login,那么开发者可以使用 bar/123 和 javaboy/123 两个用户进行登录。登录效果如图4-8 所示(注意登录路径是 /bar/login)。

再来看 SecurityConfig02。在 Security02 中,我们设置过滤器链的拦截规则是 /foo/**
,即如果请求路径是 /foo/**
格式的,则进入到 Security02 的过滤器链中进行处理,同时我们配置了局部 AuthenticationManager 对应的用户是 foo/123,由于重写了 configure(AuthenticationManagerBuilder) 方法,在该方法中定义了局部 AuthenticationManager 的 parent 对应的用户,此时注册到 Spring 容器中的 UserDetailsService 实例对于 /foo/**
过滤器链不再生效。换句话说,如果登录路径是 /foo/login,开发者可以使用 foo/123 和 javagirl/123 两个用户进行登录,而不可以使用 javaboy/123 进行登录。登录效果如图4-9所示(注意登录路径是 /foo/login)。

需要注意的是,如果配置了多个过滤器链,需要使用 @Order 注解来标记不同配置的优先级(即不同过滤虑器链的优先级),数字越大优先级越低。当请求到来时,会按照过滤器链的优先级从高往低,依次进行匹配。