SpringSecurity是通过filter实现其功能。其会创建一个名springSecurityFilterChain的filter对象,实现类为FilterChanProxy。FilterChainProxy内部维护了一个集合,集合中的元素为SecurityFilterChain,SecurityFilterChain对象有两方法,一个是当前请求是否匹配,还有一个是获取匹配后的filter。当请求匹配到一个SecurityFilterChain时,SecurityFilterChain中的所有filter会被用于创建VirtualFilterChain对象,其为一个FilterChain接口的实现类。SpringSecurity可以为不同的请求配置不同的filter链。SpringSecurity的核心图:
springSecurityFilterChain是如果创建的?
@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
/**
* Creates the Spring Security Filter Chain
*/
@Bean(name = "springSecurityFilterChain")
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
}
在Springboot中可以直接向spring容器中注入filter bean完成,filter的配置,这里向spring容器中注入了名为springSecurityFilterChain的filter,从方法中可以看到是由WebSecurity.build发方法创建而来。
WebSecurit是什么?
首先看一下继承WebSecurityl继承图:
从图中可以看出WebSecurity的核心是对SecurityBuilder的实现,为了帮助我们,spring提供了AbstractSecurityBuilder、AbstractConfiguredSecurityBuilder辅助抽象类。
SecurityBuilder:
public interface SecurityBuilder {
/**
* Builds the object and returns it or null.
*/
O build() throws Exception;
}
接口很简单,就一个build方法,简明扼要,就是用来创建一个对象。
AbstractSecurityBuilder:
public abstract class AbstractSecurityBuilder implements SecurityBuilder {
private AtomicBoolean building = new AtomicBoolean();
private O object;
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
protected abstract O doBuild() throws Exception;
public final O getObject() {
return this.object;
}
}
该类作用也是否简单,就是防止对象被重复创建 。
AbstractConfiguredSecurityBuilder
public abstract class AbstractConfiguredSecurityBuilder>
extends AbstractSecurityBuilder {
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit();
init();
buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
buildState = BuildState.BUILDING;
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
private void init() throws Exception {
Collection> configurers = getConfigurers();
for (SecurityConfigurer configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
private void configure() throws Exception {
Collection> configurers = getConfigurers();
for (SecurityConfigurer configurer : configurers) {
configurer.configure((B) this);
}
}
}
该类通过实现doBuild方法来创建一个对象,该类由两个重要的功能:
1、对创建对象的步骤进一步细分。由于创建一个对象可能比较复杂,可能要先初始化、配置必要参数等,然后才能创建对象。所以doBuild 放方法进行了拆分,拆分成:beforeInit、init、beforeConfigure、configure、performBuild等步骤,performBuild才是用来创建对象。
2、配置创建的对象所必须的条件,SecurityBuilder类及其子类是用来创建对象的,简称为:对象创建器。通过配置不同的参数给对象创建器,于是就可以达到创建不同功能对象的目的。从代码中可以看到,SecurityBuilder对象创建器获取了所以适合的SecurityBuilder配置器,每个配置器都会对 对象创建器进行配置。
SecurityBuilder配置器:
public interface SecurityConfigurer> {
/**
* 初始化SecurityBuilder
*/
void init(B builder) throws Exception;
/**
* 配置SecurityBuilder
*/
void configure(B builder) throws Exception;
}
SpringSecurity中经常出现SecurityBuilder和SecurityConfigurer配合来创建对象。
言归正传,springSecurityFilterChain是一个filter,他由WebSecurity.build创建而来,WebSecurity实现了SecurityBuilder接口,因此WebSecurity是一个用于创建filter的对象创建器。
WebSecurity:
public final class WebSecurity extends
AbstractConfiguredSecurityBuilder implements
SecurityBuilder, ApplicationContextAware {
@Override
protected Filter performBuild() throws Exception {
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List securityFilterChains = new ArrayList<>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
postBuildAction.run();
return result;
}
}
WebSecurity在创建FilterChainProxy 对象时会传入SecurityFilterChain集合。这样FilterChainProxy 就可为不同的请求配置不同的过滤器链。
public class FilterChainProxy extends GenericFilterBean {
private List filterChains;
public FilterChainProxy(List filterChains) {
this.filterChains = filterChains;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
else {
doFilterInternal(request, response, chain);
}
}
private void doFilterInternal(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FirewalledRequest fwRequest = firewall
.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse fwResponse = firewall
.getFirewalledResponse((HttpServletResponse) response);
List filters = getFilters(fwRequest);
if (filters == null || filters.size() == 0) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(fwRequest)
+ (filters == null ? " has no matching filters"
: " has an empty filter list"));
}
fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
return;
}
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
/**
* 获取配置的filter集合.
*/
private List getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
}
下面通过一个简单的实例验证一下:
maven引入jar包
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-security
两个接口,接口不同,使用的过滤器链也不同:
@RestController
public class MyController {
@RequestMapping(value = {"/cat"})
public String cat() {
System.out.println("cat service");
return "cat service";
}
@RequestMapping(value = {"/dog"})
public String dog() {
System.out.println("dog service");
return "dog service";
}
}
/cat 接口的过滤器链创建器:
public class CatSecurityFilterChainBuilder extends AbstractConfiguredSecurityBuilder{
public CatSecurityFilterChainBuilder(ObjectPostProcessor
/dog 接口的过滤器链创建器:
public class DogSecurityFilterChainBuilder extends AbstractConfiguredSecurityBuilder{
public DogSecurityFilterChainBuilder(ObjectPostProcessor objectPostProcessor) {
super(objectPostProcessor);
}
public DogSecurityFilterChainBuilder(ObjectPostProcessor objectPostProcessor, boolean allowConfigurersOfSameType) {
super(objectPostProcessor, allowConfigurersOfSameType);
}
@Override
protected SecurityFilterChain performBuild() throws Exception {
RequestMatcher dogRequestMatcher=new AntPathRequestMatcher("/dog/**", null);
Filter dogFilter1= new Filter() {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("dogFilter1 start");
chain.doFilter(request,response);
System.out.println("dogFilter1 end");
}
};
Filter dogFilter2= new Filter() {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("dogFilter2 start");
chain.doFilter(request,response);
System.out.println("dogFilter2 end");
}
};
SecurityFilterChain securityFilterChain=new DefaultSecurityFilterChain(dogRequestMatcher,dogFilter1,dogFilter2);
return securityFilterChain;
}
}
继承WebSecurityConfigurerAdapter,覆盖其init方法,WebSecurityConfigurerAdapter的init方法默认会添加一个SecurityFilterChain的创建器(HttpSecurity),这里我们不需要。添加我们自己做好的两个SecurityFilterChain的创建器。
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
public void init(WebSecurity web) throws Exception {
//WebSecurityConfigurerAdapter中的init方法会默认注入SecurityFilterChain的创建器(HttpSecurity),这里我们不需要,注释掉。
//super.init(web);
ObjectPostProcessor objectPostProcessor = new ObjectPostProcessor() {
@Override
public Object postProcess(Object object) {
return object;
}
};
web.addSecurityFilterChainBuilder(new CatSecurityFilterChainBuilder(objectPostProcessor));
web.addSecurityFilterChainBuilder(new DogSecurityFilterChainBuilder(objectPostProcessor));
}
}
测试:
SpringSecurity十分精巧,我们只需要关心,什么类型的请求使用什么类型的过滤器链。
你会发现你的主要任务就是创建SecurityFilterChain创建器,由其创建SecurityFilterChain。
SecurityFilterChain创建器,String也为我们提供了一个HttpSecurity。
下一章节我们将分析HttpSecurity