SpringSecurity的配置详解——websecurity

Websecurity类主要的继承关系为自Websecurity->AbstractConfiguredSecurityBuilder->AbstractSecurityBuilder,其中上一步调用的build方法就在AbstractSecurityBuilder中 

SpringSecurity在这个类中实现了创建FilterChain的方法——performbuild

/***
*在生成发生后立即执行可运行文件*
*@参数后期生成操作
*@返回@link websecurity进行进一步的自定义
*/
@Override
	protected Filter performBuild() throws Exception {
		Assert.state(
				!securityFilterChainBuilders.isEmpty(),
				"At least one SecurityBuilder needs to be specified. Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke "
						+ WebSecurity.class.getSimpleName()
						+ ".addSecurityFilterChainBuilder directly");
		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;
		if (debugEnabled) {
			logger.warn("\n\n"
					+ "********************************************************************\n"
					+ "**********        Security debugging is enabled.       *************\n"
					+ "**********    This may include sensitive information.  *************\n"
					+ "**********      Do not use in a production system!     *************\n"
					+ "********************************************************************\n\n");
			result = new DebugFilter(filterChainProxy);
		}
		postBuildAction.run();
		return result;
	}

 

在构建FilterChain的过程中,我们可以发现使用了两个关键的对象——ignoredRequest和securityFilterChainBuilders:

int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List securityFilterChains = new ArrayList(
      chainSize);
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();

首先,我们来看一看securityFilterChainBuilders:

在WebSecurityConfigureAdapter类中的init方法中有如下语句:

final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http)

也就是说,这个securityFilterChainBuilders中存放的是获取到的httpSecurity实例对象(此处应该注意的是虽然我们的http对象是通过一种"add"的形式添加到securityFilterChainBuilders中的,但是,通过阅读WebSecurityConfigureAdapter的getHttp()方法中的代码我们可以知道一个WebSecurityConfigureAdapter类中通过getHttp()方法只会获得一个http实例——)

之后我们通过阅读HttpSecurity类的代码可以知道,这个http实例中包含了我们创建过滤器链所需要的各种过滤器的配置类的实例;

那么,既然我们创建FilterChain所需要的配置实例已经包含进来了,这个ignoredRequests到底是什么呢??

我们可以查看一下它的源码:
private final List ignoredRequests = new ArrayList();

在这里我们可以看出ignoredRequests对象是一个RequestMatcher对象的列表,再来看看RequestMatcher:
 

public interface RequestMatcher {

   /**
    * Decides whether the rule implemented by the strategy matches the supplied request.
    *
    * @param request the request to check for a match
    * @return true if the request matches, false otherwise
    */
   boolean matches(HttpServletRequest request);

}

这是一个接口,其中注释的意思是——

决定策略实现的规则是否与提供的请求匹配。

@param请求检查匹配的请求

@如果请求匹配,则返回true,否则返回false

之后,这是创建过滤器链的代码:
 

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());
}
public final class WebSecurity extends
		AbstractConfiguredSecurityBuilder implements
		SecurityBuilder, ApplicationContextAware {
	private final Log logger = LogFactory.getLog(getClass());

	private final List ignoredRequests = new ArrayList();

	private final List> securityFilterChainBuilders = new ArrayList>();

	private IgnoredRequestConfigurer ignoredRequestRegistry;

	private FilterSecurityInterceptor filterSecurityInterceptor;

	private HttpFirewall httpFirewall;

	private boolean debugEnabled;

	private WebInvocationPrivilegeEvaluator privilegeEvaluator;

	private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();

	private SecurityExpressionHandler expressionHandler = defaultWebSecurityExpressionHandler;

	private Runnable postBuildAction = new Runnable() {
		public void run() {
		}
	};

	/**
	 * Creates a new instance
	 * @param objectPostProcessor the {@link ObjectPostProcessor} to use
	 * @see WebSecurityConfiguration
	 */
	public WebSecurity(ObjectPostProcessor objectPostProcessor) {
		super(objectPostProcessor);
	}

	/**
	 * 

* Allows adding {@link RequestMatcher} instances that Spring Security * should ignore. Web Security provided by Spring Security (including the * {@link SecurityContext}) will not be available on {@link HttpServletRequest} that * match. Typically the requests that are registered should be that of only static * resources. For requests that are dynamic, consider mapping the request to allow all * users instead. *

* * Example Usage: * *
	 * webSecurityBuilder.ignoring()
	 * // ignore all URLs that start with /resources/ or /static/
	 * 		.antMatchers("/resources/**", "/static/**");
	 * 
* * Alternatively this will accomplish the same result: * *
	 * webSecurityBuilder.ignoring()
	 * // ignore all URLs that start with /resources/ or /static/
	 * 		.antMatchers("/resources/**").antMatchers("/static/**");
	 * 
* * Multiple invocations of ignoring() are also additive, so the following is also * equivalent to the previous two examples: * *
	 * webSecurityBuilder.ignoring()
	 * // ignore all URLs that start with /resources/
	 * 		.antMatchers("/resources/**");
	 * webSecurityBuilder.ignoring()
	 * // ignore all URLs that start with /static/
	 * 		.antMatchers("/static/**");
	 * // now both URLs that start with /resources/ and /static/ will be ignored
	 * 
* * @return the {@link IgnoredRequestConfigurer} to use for registering request that * should be ignored */ public IgnoredRequestConfigurer ignoring() { return ignoredRequestRegistry; } /** * Allows customizing the {@link HttpFirewall}. The default is * {@link DefaultHttpFirewall}. * * @param httpFirewall the custom {@link HttpFirewall} * @return the {@link WebSecurity} for further customizations */ public WebSecurity httpFirewall(HttpFirewall httpFirewall) { this.httpFirewall = httpFirewall; return this; } /** * Controls debugging support for Spring Security. * * @param debugEnabled if true, enables debug support with Spring Security. Default is * false. * * @return the {@link WebSecurity} for further customization. * @see EnableWebSecurity#debug() */ public WebSecurity debug(boolean debugEnabled) { this.debugEnabled = debugEnabled; return this; } /** *

* Adds builders to create {@link SecurityFilterChain} instances. *

* *

* Typically this method is invoked automatically within the framework from * {@link WebSecurityConfigurerAdapter#init(WebSecurity)} *

* * @param securityFilterChainBuilder the builder to use to create the * {@link SecurityFilterChain} instances * @return the {@link WebSecurity} for further customizations */ public WebSecurity addSecurityFilterChainBuilder( SecurityBuilder securityFilterChainBuilder) { this.securityFilterChainBuilders.add(securityFilterChainBuilder); return this; } /** * Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is null, then a * {@link DefaultWebInvocationPrivilegeEvaluator} will be created when * {@link #securityInterceptor(FilterSecurityInterceptor)} is non null. * * @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use * @return the {@link WebSecurity} for further customizations */ public WebSecurity privilegeEvaluator( WebInvocationPrivilegeEvaluator privilegeEvaluator) { this.privilegeEvaluator = privilegeEvaluator; return this; } /** * Set the {@link SecurityExpressionHandler} to be used. If this is null, then a * {@link DefaultWebSecurityExpressionHandler} will be used. * * @param expressionHandler the {@link SecurityExpressionHandler} to use * @return the {@link WebSecurity} for further customizations */ public WebSecurity expressionHandler( SecurityExpressionHandler expressionHandler) { Assert.notNull(expressionHandler, "expressionHandler cannot be null"); this.expressionHandler = expressionHandler; return this; } /** * Gets the {@link SecurityExpressionHandler} to be used. * @return */ public SecurityExpressionHandler getExpressionHandler() { return expressionHandler; } /** * Gets the {@link WebInvocationPrivilegeEvaluator} to be used. * @return */ public WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() { if (privilegeEvaluator != null) { return privilegeEvaluator; } return filterSecurityInterceptor == null ? null : new DefaultWebInvocationPrivilegeEvaluator(filterSecurityInterceptor); } /** * Sets the {@link FilterSecurityInterceptor}. This is typically invoked by * {@link WebSecurityConfigurerAdapter}. * @param securityInterceptor the {@link FilterSecurityInterceptor} to use * @return the {@link WebSecurity} for further customizations */ public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) { this.filterSecurityInterceptor = securityInterceptor; return this; } /** * Executes the Runnable immediately after the build takes place * * @param postBuildAction * @return the {@link WebSecurity} for further customizations */ public WebSecurity postBuildAction(Runnable postBuildAction) { this.postBuildAction = postBuildAction; return this; } @Override protected Filter performBuild() throws Exception { Assert.state( !securityFilterChainBuilders.isEmpty(), "At least one SecurityBuilder needs to be specified. Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly"); 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; if (debugEnabled) { logger.warn("\n\n" + "********************************************************************\n" + "********** Security debugging is enabled. *************\n" + "********** This may include sensitive information. *************\n" + "********** Do not use in a production system! *************\n" + "********************************************************************\n\n"); result = new DebugFilter(filterChainProxy); } postBuildAction.run(); return result; } /** * An {@link IgnoredRequestConfigurer} that allows optionally configuring the * {@link MvcRequestMatcher#setMethod(HttpMethod)} * * @author Rob Winch */ public final class MvcMatchersIgnoredRequestConfigurer extends IgnoredRequestConfigurer { private final List mvcMatchers; private MvcMatchersIgnoredRequestConfigurer(ApplicationContext context, List mvcMatchers) { super(context); this.mvcMatchers = mvcMatchers; } public IgnoredRequestConfigurer servletPath(String servletPath) { for (MvcRequestMatcher matcher : this.mvcMatchers) { matcher.setServletPath(servletPath); } return this; } } /** * Allows registering {@link RequestMatcher} instances that should be ignored by * Spring Security. * * @author Rob Winch * @since 3.2 */ public class IgnoredRequestConfigurer extends AbstractRequestMatcherRegistry { private IgnoredRequestConfigurer(ApplicationContext context) { setApplicationContext(context); } @Override public MvcMatchersIgnoredRequestConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) { List mvcMatchers = createMvcMatchers(method, mvcPatterns); WebSecurity.this.ignoredRequests.addAll(mvcMatchers); return new MvcMatchersIgnoredRequestConfigurer(getApplicationContext(), mvcMatchers); } @Override public MvcMatchersIgnoredRequestConfigurer mvcMatchers(String... mvcPatterns) { return mvcMatchers(null, mvcPatterns); } @Override protected IgnoredRequestConfigurer chainRequestMatchers( List requestMatchers) { WebSecurity.this.ignoredRequests.addAll(requestMatchers); return this; } /** * Returns the {@link WebSecurity} to be returned for chaining. */ public WebSecurity and() { return WebSecurity.this; } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.defaultWebSecurityExpressionHandler .setApplicationContext(applicationContext); this.ignoredRequestRegistry = new IgnoredRequestConfigurer(applicationContext); } }

可以看到build过程主要分三步,init->configure->peformBuild

[*]第一步 init
在init方法中,会调用设置好的SecurityConfigurer列表中每一个configurer的init方法,这个SecurityConfigurer列表就是我们在WebSecurityConfiguration类中通过调用apply()方法设置进来的,即WebSecurityConfigurerAdapter这个类或者是我们继承了WebSecurityConfigurerAdapter的类。

WebSecurityConfigurerAdapter类(最重要的一个类,我们定制化也是继承这个类进行设置的)

[*] 第二步configure
configure方法最终也调用到了WebSecurityConfigurerAdapter的configure(WebSecurity web)方法,默认实现中这个是一个空方法,具体应用中也经常重写这个方法来实现特定需求。

[*] 第三部 peformBuild
具体的实现逻辑在WebSecurity类中,这个方法中最主要的任务就是遍历securityFilterChainBuilders属性中的SecurityBuilder对象,并调用他的build方法。
这个securityFilterChainBuilders属性我们前面也有提到过,就是在WebSecurityConfigurerAdapter类的init方法中获取http后赋值给了WebSecurity。因此这个地方就是调用httpSecurity的build方法。
 

你可能感兴趣的:(Spring)