赞
踩
WebSecurity
是Spring Security
的一个SecurityBuilder
。它的任务是基于一组WebSecurityConfigurer
构建出一个Servlet Filter
,具体来讲就是构建一个Spring Security
的FilterChainProxy
实例。这个FilterChainProxy
实现了Filter
接口,也是通常我们所说的Spring Security Filter Chain
,所构建的FilterChainProxy
实例缺省会使用名称springSecurityFilterChain
作为bean
注册到容器,运行时处理web
请求过程中会使用该bean
进行安全控制。
每个FilterChainProxy
包装了一个HttpFirewall
和若干个SecurityFilterChain
, 这里每个 SecurityFilterChain
要么对应于一个要忽略安全控制的URL
通配符(RequestMatcher
);要么对应于一个要进行安全控制的URL
通配符(HttpSecurity
)。
助记公式 :
1 FilterChainProxy = 1 HttpFirewall + n SecurityFilterChain
WebSecurity
构建目标FilterChainProxy
所使用的WebSecurityConfigurer
实现类通常会继承自WebSecurityConfigurerAdapter
(当然也可以完全实现接口WebSecurityConfigurer
)。每个WebSecurityConfigurerAdapter
可以配置若干个要忽略安全控制的URL
通配符(RequestMatcher
)和一个要进行安全控制的URL
通配符(HttpSecurity
)。
助记公式 :
1 WebSecurity = 1 HttpFirewall + x HttpSecurity (securityFilterChainBuilders) + y RequestMatcher (ignoredRequests)
- 这里
1 HttpSecurity
对应1
个URL pattern
,用于匹配一组需要进行安全配置的请求;- 这里
1 RequestMatcher
对应1
个URL pattern
,用于匹配一组需要忽略安全控制的请求,比如静态公开资源或者其他动态公开资源;- 这里的每个
HttpSecurity
或者RequestMatcher
最终对应构建一个SecurityFilterChain
,这里x+y
会等于上面助记公式中的n
;1 WebSecurity
最终用于构建1 FilterChainProxy
,WebSecurity
的HttpFirewall
如果不存在,则目标FilterChainProxy
会使用缺省值,一个StrictHttpFirewall
;- 每个
WebSecurity
虽然允许设置多个securityFilterChainBuilder
,但Spring Security
在一个WebSecurityConfigurerAdapter
中缺省只向其中添加一个securityFilterChainBuilder
也就是HttpSecurity
。
开发人员可以在应用中提供多个WebSecurityConfigurerAdapter
用于配置Spring Web Security
,但要注意它们的优先级必须不同,这一点可以通过@Order
注解来设置。
package org.springframework.security.config.annotation.web.builders; // 这里省略了各个 import 导入行 /** * * WebSecurity 由 WebSecurityConfiguration 创建,用于创建 FilterChainProxy, 这个 FilterChainProxy * 也就是通常我们所说的 Spring Security Filter Chain (springSecurityFilterChain)。 * springSecurityFilterChain 是一个 Servlet 过滤器 Filter, DelegatingFilterProxy 会把真正的 * 安全处理逻辑代理给这个 Filter 。 * * 通过创建一个或者多个 WebSecurityConfigurer, 或者重写 WebSecurityConfigurerAdapter 的某些方法, * 可以对 WebSecurity 进行定制。 * * * @see EnableWebSecurity * @see WebSecurityConfiguration * * @author Rob Winch * @since 3.2 */ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter>, ApplicationContextAware { private final Log logger = LogFactory.getLog(getClass()); // 记录开发人员通过类似下面例子语句指定忽略的URL : // webSecurity.ignoring().antMatchers("/images/**", "/favicon.ico") // 在该例子中,会在 ignoredRequests 添加两个元素,分别对应 /images/**, /favicon.ico private final List<RequestMatcher> ignoredRequests = new ArrayList<RequestMatcher>(); // 最终被构建目标对象FilterChainProxy管理的多个安全过滤器链 SecurityFilterChain 的构建器列表, // 每个构建器用于构建一个 SecurityFilterChain private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<SecurityBuilder<? extends SecurityFilterChain>>(); private IgnoredRequestConfigurer ignoredRequestRegistry; private FilterSecurityInterceptor filterSecurityInterceptor; private HttpFirewall httpFirewall; private boolean debugEnabled; private WebInvocationPrivilegeEvaluator privilegeEvaluator; // 初始化缺省的Web安全表达式处理器 private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); // 实际使用的Web安全表达式处理器,缺省设置为使用缺省的Web安全表达式处理器 private SecurityExpressionHandler<FilterInvocation> expressionHandler = defaultWebSecurityExpressionHandler; private Runnable postBuildAction = new Runnable() { public void run() { } }; /** * Creates a new instance * @param objectPostProcessor theObjectPostProcessor to use , 用于对象初始化和设置对象的销毁 * @see WebSecurityConfiguration */ public WebSecurity(ObjectPostProcessor<Object> objectPostProcessor) { super(objectPostProcessor); } /** * * Allows addingRequestMatcher instances that Spring Security * should ignore. Web Security provided by Spring Security (including the * SecurityContext) will not be available on 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 IgnoredRequestConfigurer to use for registering request that * should be ignored */ public IgnoredRequestConfigurer ignoring() { return ignoredRequestRegistry; } /** * Allows customizing the HttpFirewall. The default is * DefaultHttpFirewall. * * @param httpFirewall the custom HttpFirewall * @return the WebSecurity for further customizations */ public WebSecurity httpFirewall(HttpFirewall httpFirewall) { this.httpFirewall = httpFirewall; return this; } /** * Controls debugging support for Spring Security. * * 是否启用了调试模式,来自注解 @EnableWebSecurity 的属性 debug,缺省值 false * @param debugEnabled if true, enables debug support with Spring Security. Default is * false. * * @return the WebSecurity for further customization. * @see EnableWebSecurity#debug() */ public WebSecurity debug(boolean debugEnabled) { this.debugEnabled = debugEnabled; return this; } /** * * Adds builders to create SecurityFilterChain instances. * * * * Typically this method is invoked automatically within the framework from * WebSecurityConfigurerAdapter#init(WebSecurity) * * * @param securityFilterChainBuilder the builder to use to create the * SecurityFilterChain instances * @return the WebSecurity for further customizations */ public WebSecurity addSecurityFilterChainBuilder( SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) { this.securityFilterChainBuilders.add(securityFilterChainBuilder); return this; } /** * Set the WebInvocationPrivilegeEvaluator to be used. If this is null, then a * DefaultWebInvocationPrivilegeEvaluator will be created when * #securityInterceptor(FilterSecurityInterceptor) is non null. * * @param privilegeEvaluator the WebInvocationPrivilegeEvaluator to use * @return the WebSecurity for further customizations */ public WebSecurity privilegeEvaluator( WebInvocationPrivilegeEvaluator privilegeEvaluator) { this.privilegeEvaluator = privilegeEvaluator; return this; } /** * 设置实际要使用的 SecurityExpressionHandler. 如果不设置,则缺省使用 * DefaultWebSecurityExpressionHandler . * * @param expressionHandler the SecurityExpressionHandler to use * @return the WebSecurity for further customizations */ public WebSecurity expressionHandler( SecurityExpressionHandler<FilterInvocation> expressionHandler) { Assert.notNull(expressionHandler, "expressionHandler cannot be null"); this.expressionHandler = expressionHandler; return this; } /** * Gets the SecurityExpressionHandler to be used. * @return */ public SecurityExpressionHandler<FilterInvocation> getExpressionHandler() { return expressionHandler; } /** * Gets the WebInvocationPrivilegeEvaluator to be used. * @return */ public WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() { if (privilegeEvaluator != null) { return privilegeEvaluator; } return filterSecurityInterceptor == null ? null : new DefaultWebInvocationPrivilegeEvaluator(filterSecurityInterceptor); } /** * Sets the FilterSecurityInterceptor. This is typically invoked by * WebSecurityConfigurerAdapter. * @param securityInterceptor the FilterSecurityInterceptor to use * @return the WebSecurity for further customizations */ public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) { this.filterSecurityInterceptor = securityInterceptor; return this; } /** * Executes the Runnable immediately after the build takes place * 指定一段逻辑,以Runnable形式组织,在 build 完成后立即执行,该类实际上是放在 performBuild() * 函数结束前执行的 * * @param postBuildAction * @return the WebSecurity for further customizations */ public WebSecurity postBuildAction(Runnable postBuildAction) { this.postBuildAction = postBuildAction; return this; } /** * 各种配置信息已经搜集齐备,通过该方法执行构建过程,构建 Filter FilterChainProxy 实例并返回该 Filter **/ @Override protected Filter performBuild() throws Exception { Assert.state( !securityFilterChainBuilders.isEmpty(), "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. " + "Typically this done by adding a @Configuration that extends " + " WebSecurityConfigurerAdapter." + " More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly"); // 计算出要创建的过滤器链 SecurityFilterChain 的个数 : // ignoredRequests 中URL通配符的个数 + securityFilterChainBuilders元素的个数, // 这里每个 securityFilterChainBuilders 元素实际上是一个 HttpSecurity int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size(); List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>( chainSize); // 对于每个要忽略的URL通配符,构建一个 SecurityFilterChain 实例,使用的实现类为 // DefaultSecurityFilterChain , 该实现类实例初始化时不包含任何过滤器,从而对给定的URL, // 可以达到不对其进行安全检查的目的 for (RequestMatcher ignoredRequest : ignoredRequests) { securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest)); } // 对每个 securityFilterChainBuilder 执行其构建过程,生成一个 securityFilterChain, // 这里每个 securityFilterChainBuilders 元素实际上是一个 HttpSecurity for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); } // 由多个 SecurityFilterChain securityFilterChains 构造一个 FilterChainProxy,这就是最终要构建的 // Filter : FilterChainProxy : springSecurityFilterChain FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); if (httpFirewall != null) { filterChainProxy.setFirewall(httpFirewall); } // 对根据配置新建的 filterChainProxy 进行验证, // FilterChainProxy 的缺省验证器是一个 NullFilterChainValidator,相应的验证逻辑为空方法 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 IgnoredRequestConfigurer that allows optionally configuring the * MvcRequestMatcher#setMethod(HttpMethod) * * @author Rob Winch */ public final class MvcMatchersIgnoredRequestConfigurer extends IgnoredRequestConfigurer { private final List<MvcRequestMatcher> mvcMatchers; private MvcMatchersIgnoredRequestConfigurer(ApplicationContext context, List<MvcRequestMatcher> mvcMatchers) { super(context); this.mvcMatchers = mvcMatchers; } public IgnoredRequestConfigurer servletPath(String servletPath) { for (MvcRequestMatcher matcher : this.mvcMatchers) { matcher.setServletPath(servletPath); } return this; } } /** * 嵌套类,用于注册 Spring Security 需要忽略的 RequestMatcher 实例 * * @author Rob Winch * @since 3.2 */ public class IgnoredRequestConfigurer extends AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> { private IgnoredRequestConfigurer(ApplicationContext context) { setApplicationContext(context); } @Override public MvcMatchersIgnoredRequestConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) { List<MvcRequestMatcher> 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<RequestMatcher> requestMatchers) { WebSecurity.this.ignoredRequests.addAll(requestMatchers); return this; } /** * 返回当前 WebSecurity 实例,方便链式调用. */ public WebSecurity and() { return WebSecurity.this; } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.defaultWebSecurityExpressionHandler .setApplicationContext(applicationContext); this.ignoredRequestRegistry = new IgnoredRequestConfigurer(applicationContext); } }
WebSecurity
及其基类之间的关系Spring Security : 配置 HttpSecurity 的 SecurityConfigurer
Spring Security : 安全构建器HttpSecurity和WebSecurity的区别
Spring Security : HTTP请求安全构建器 HttpSecurity
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。