我希望通过加入一些代码来为伟大的答案做出贡献。在Spring Security中,有三个非常重要的Bean,它们是
DelegatingFilterProxy
、
FilterChainProxy
和
SecurityFilterChain
。根据它们的类型,
DelegatingFilterProxy
将过滤请求的工作委派给一个名为
springSecurityFilterChain
的
FilterChainProxy
Bean,并且
FilterChainProxy
的配置如下:
@Bean(
name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
return (Filter)this.webSecurity.build();
}
springSecurityFilterChain
(或FilterChainProxy
)本身有一个SecurityFilterChain
列表。 SecurityFilterChain
本身有一个实现实际逻辑的Filter
实例列表。
每次我们扩展WebSecurityConfigurerAdapter
并重写configure(HttpSecurity httpSecurity)
方法时,实际上创建了一个SecurityFilterChain
,该链将被springSecurityFilterChain
使用。
springSecurityFilterChain
如何从列表中选择适当的SecurityFilterChain
? 基于在SecurityFilterChain
接口中定义的boolean matches(HttpServletRequest request)
方法。
因此,HttpSecurity
用于创建自定义的SecurityFilterChain
。
那么WebSecurity
实际上是什么时候发挥作用的呢? WebSecurity
实际上允许我们自定义springSecurityFilterChain
(或FilterChainProxy
)。看一下如何创建springSecurityFilterChain
。
创建springSecurityFilterChain
bean 调用的是WebSecurity
的performBuild
方法。
@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");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> 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;
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;
}
正如您所看到的,当Spring想要将
SecurityFilterChain
注册到每个
web.ignoring()....
的
springSecurityFilterChain
bean中时,Spring会将一个
DefaultSecurityFilterChain
添加到列表
开头,而这个
DefaultSecurityFilterChain
是
SecurityFilterChain
的自定义实现。
当请求到来时,
springSecurityFilterChain
将按顺序检查其
SecurityFilterChain
列表,以委托过滤工作给该
SecurityFilterChain
。
springSecurityFilterChain
将调用每个
SecurityFilterChain
的
match
方法。如果请求URL以"/resources/**"开头,则在列表开头添加的自定义
SecurityFilterChain
和我们定制的
SecurityFilterChain
实例将负责过滤请求。
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
完全被忽略。
configure(HttpSecurity http)
是否完全被忽略了,因为configure(WebSecurity web)
已经指定所有相同的端点应该被忽略了? - Robert Mark Bramconfigure(WebSecurity web)
中声明的端点将完全被忽略,但像禁用csrf和检查除"/login", "/register", "/api/public/**"
之外的所有其他请求的其他配置仍然有效。 - Ubaid ur Rehman