当前位置:   article > 正文

Spring Security : Web安全构建器 WebSecurity

websecurity

WebSecuritySpring Security的一个SecurityBuilder。它的任务是基于一组WebSecurityConfigurer构建出一个Servlet Filter,具体来讲就是构建一个Spring SecurityFilterChainProxy实例。这个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. 这里 1 HttpSecurity 对应1URL pattern,用于匹配一组需要进行安全配置的请求;
  2. 这里 1 RequestMatcher 对应 1URL pattern,用于匹配一组需要忽略安全控制的请求,比如静态公开资源或者其他动态公开资源;
  3. 这里的每个 HttpSecurity或者RequestMatcher最终对应构建一个SecurityFilterChain,这里 x+y 会等于上面助记公式中的 n
  4. 1 WebSecurity最终用于构建1 FilterChainProxy, WebSecurityHttpFirewall如果不存在,则目标FilterChainProxy会使用缺省值,一个StrictHttpFirewall
  5. 每个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);
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362

WebSecurity及其基类之间的关系

WebSecurity类图

参考文章

Spring Security : 配置 HttpSecurity 的 SecurityConfigurer
Spring Security : 安全构建器HttpSecurity和WebSecurity的区别
Spring Security : HTTP请求安全构建器 HttpSecurity

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/933969
推荐阅读
相关标签
  

闽ICP备14008679号