学习springSecurit第一节-主体结构

 SpringSecurity是通过filter实现其功能。其会创建一个名springSecurityFilterChain的filter对象,实现类为FilterChanProxy。FilterChainProxy内部维护了一个集合,集合中的元素为SecurityFilterChain,SecurityFilterChain对象有两方法,一个是当前请求是否匹配,还有一个是获取匹配后的filter。当请求匹配到一个SecurityFilterChain时,SecurityFilterChain中的所有filter会被用于创建VirtualFilterChain对象,其为一个FilterChain接口的实现类。SpringSecurity可以为不同的请求配置不同的filter链。SpringSecurity的核心图:学习springSecurit第一节-主体结构_第1张图片

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继承图:

学习springSecurit第一节-主体结构_第2张图片

 从图中可以看出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 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 objectPostProcessor) {
        super(objectPostProcessor);
    }

    public CatSecurityFilterChainBuilder(ObjectPostProcessor objectPostProcessor, boolean allowConfigurersOfSameType) {
        super(objectPostProcessor, allowConfigurersOfSameType);
    }

    @Override
    protected SecurityFilterChain performBuild() throws Exception {
        RequestMatcher catRequestMatcher=new AntPathRequestMatcher("/cat/**", null);
        Filter catFilter1=  new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                System.out.println("catFilter1 start");
                chain.doFilter(request,response);
                System.out.println("catFilter1 end");

            }
        };
        Filter catFilter2=  new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                System.out.println("catFilter2 start");
                chain.doFilter(request,response);
                System.out.println("catFilter2 end");


            }
        };
        SecurityFilterChain securityFilterChain=new DefaultSecurityFilterChain(catRequestMatcher,catFilter1,catFilter2);
        return securityFilterChain;
    }
}
 
  

 /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));
    }

}

测试:

学习springSecurit第一节-主体结构_第3张图片   学习springSecurit第一节-主体结构_第4张图片

 

SpringSecurity十分精巧,我们只需要关心,什么类型的请求使用什么类型的过滤器链。

你会发现你的主要任务就是创建SecurityFilterChain创建器,由其创建SecurityFilterChain。

SecurityFilterChain创建器,String也为我们提供了一个HttpSecurity。

下一章节我们将分析HttpSecurity 

 

 

 

 

 

你可能感兴趣的:(springSecurity)