Spring Security中的所有功能都是通过过滤器来实现的,这些过滤器组成一个完整的过滤器链。过滤器链涉及很多基础组件,首先梳理一下这些关键组件,会方便理解Spring Security过滤器链。
他是一个对象后置处理器,当一个对象创建成功后,如果需要一些额外的事情需要补充,就可以通过ObjectPostProcessor来进行处理。
在Spring Security中,开发者可以灵活的配置项目中需要哪些过滤器,一旦选定过滤器之后,每个过滤器会有一个对应的配置器,叫做xxxConfigurer(例如CorsConfigurer),过滤器都是在xxxConfigurer中new出来的,然后再postProcess方法中处理一遍,就将这些过滤器注入到Spring容器中了。
public interface ObjectPostProcessor {
O postProcess(O object);
}
默认有两个继承类,继承关系如下
当一个对象被new出来以后,只要调用AutowireBeanFactoryObjectPostProcessor#postProcess方法,就可以成功注入到Spring容器中。
@Override
@SuppressWarnings("unchecked")
public T postProcess(T object) {
if (object == null) {
return null;
}
T result = null;
try {
result = (T) this.autowireBeanFactory.initializeBean(object, object.toString());
}
catch (RuntimeException ex) {
Class> type = object.getClass();
throw new RuntimeException("Could not postProcess " + object + " of type " + type, ex);
}
this.autowireBeanFactory.autowireBean(object);
if (result instanceof DisposableBean) {
this.disposableBeans.add((DisposableBean) result);
}
if (result instanceof SmartInitializingSingleton) {
this.smartSingletons.add((SmartInitializingSingleton) result);
}
return result;
}
他是一个组合的对象后置处理器,维护了一个List集合,存放了所有的后置处理器。在Spring Security框架中,最终使用的对象后置处理器其实就是CompositeObjectPostProcessor,他里面的集合默认只有一个对象,就是AutowireBeanFactoryObjectPostProcessor。
private static final class CompositeObjectPostProcessor implements ObjectPostProcessor
SecurityFilterChain是Spring Security中的过滤器链对象
public interface SecurityFilterChain {
//用来判断request请求是否应该被当前过滤器链处理
boolean matches(HttpServletRequest request);
//如果matches返回true,那么request请求就会在getFilters方法返回的Filter集合中被处理
List getFilters();
}
他的默认实现类是DefaultSecurityFilterChain,需要注意的点是,在一个Spring Security项目中,SecurityFilterChain实例可能有多个。
//省略部分代码
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
private final RequestMatcher requestMatcher;
private final List filters;
@Override
public List getFilters() {
return this.filters;
}
@Override
public boolean matches(HttpServletRequest request) {
return this.requestMatcher.matches(request);
}
}
Spring Security中很多对象都可以通过SecurityBuilder来构建,源码如下:
public interface SecurityBuilder {
O build() throws Exception;
}
用来构建HttpSecurity对象,最终构建出来的对象为DefaultSecurityFilterChain,默认构建后的filter顺序如下:
HttpSecurityBuilder源码如下:
//HttpSecurityBuilder默认实现类只有HttpSecurity,可以把H当作HttpSecurity
public interface HttpSecurityBuilder> extends SecurityBuilder {
> C getConfigurer(Class clazz);
> C removeConfigurer(Class clazz);
//设置可以在多个配置器之间共享的对象
void setSharedObject(Class sharedType, C object);
C getSharedObject(Class sharedType);
//配置认证器AuthenticationProvider
H authenticationProvider(AuthenticationProvider authenticationProvider);
//配置数据源
H userDetailsService(UserDetailsService userDetailsService) throws Exception;
H addFilterAfter(Filter filter, Class extends Filter> afterFilter);
H addFilterBefore(Filter filter, Class extends Filter> beforeFilter);
//这个过滤器必须是Spring Security框架提供的过滤器的实例或者扩展,添加完成后,会自动进行排序
H addFilter(Filter filter);
}
AbstractSecurityBuilder实现了SecurityBuilder接口,并对build做了完善,确保只build一次。
public abstract class AbstractSecurityBuilder implements SecurityBuilder {
private AtomicBoolean building = new AtomicBoolean();
private O object;
//设置为final,确保子类不会再重写这个方法
@Override
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");
}
public final O getObject() {
if (!this.building.get()) {
throw new IllegalStateException("This object has not been built");
}
return this.object;
}
protected abstract O doBuild() throws Exception;
}
它允许securityconfigururer被应用到它。这使得修改SecurityBuilder成为一种策略,它可以被自定义,并分解成许多securityconfigururer对象,这些对象比SecurityBuilder有更具体的目标。
例如,一个SecurityBuilder可以构建一个DelegatingFilterProxy,但是一个securityconfiger可以用会话管理、基于表单的登录、授权等所需的过滤器填充SecurityBuilder。
在这个类中有一个声明了一个枚举,用来描述构建过程的不同状态。
private static enum BuildState {
UNBUILT(0),
INITIALIZING(1),
CONFIGURING(2),
BUILDING(3),
BUILT(4);
private final int order;
private BuildState(int order) {
this.order = order;
}
public boolean isInitializing() {
return INITIALIZING.order == this.order;
}
public boolean isConfigured() {
return this.order >= CONFIGURING.order;
}
}
在AbstractConfiguredSecurityBuilder中与configurers相关的部分代码如下:
public abstract class AbstractConfiguredSecurityBuilder> extends AbstractSecurityBuilder {
private final LinkedHashMap>, List>> configurers;
private final List> configurersAddedInInitializing;
private final Map, Object> sharedObjects;
private final boolean allowConfigurersOfSameType;
private BuildState buildState;
private ObjectPostProcessor
在AbstractConfiguredSecurityBuilder中与构建相关的部分代码如下:
//一边更新状态,一边执行构建方法
protected final O doBuild() throws Exception {
synchronized(this.configurers) {
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
this.beforeInit();
this.init();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
this.beforeConfigure();
this.configure();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
O result = this.performBuild();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;
return result;
}
}
protected void beforeInit() throws Exception {
}
protected void beforeConfigure() throws Exception {
}
protected abstract O performBuild() throws Exception;
//遍历所有配置类,并调用其init方法完成初始化操作
private void init() throws Exception {
Collection> configurers = getConfigurers();
for (SecurityConfigurer configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer configurer : this.configurersAddedInInitializing) {
configurer.init((B) this);
}
}
private void configure() throws Exception {
Collection> configurers = getConfigurers();
for (SecurityConfigurer configurer : configurers) {
configurer.configure((B) this);
}
}
ProviderManagerBuilder通过范型指定构建对象为AuthenticationManager
public interface ProviderManagerBuilder>
extends SecurityBuilder {
B authenticationProvider(AuthenticationProvider authenticationProvider);
}
AuthenticationManagerBuilder用来构建AuthenticationManager对象,他继承自AbstractConfiguredSecurityBuilder
public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder implements ProviderManagerBuilder {
private AuthenticationManager parentAuthenticationManager;
private List authenticationProviders = new ArrayList();
private UserDetailsService defaultUserDetailsService;
private Boolean eraseCredentials;
private AuthenticationEventPublisher eventPublisher;
//表示允许相同类型的配置类同时存在
public AuthenticationManagerBuilder(ObjectPostProcessor
HttpSecurity的主要作用是用来构建一条过滤器链,也就是构建一个DefaultSecurityFilterChain对象。一个DefaultSecurityFilterChain对象包含一个路径匹配器和多个Spring Security过滤器,HttpSecurity中通过收集各种各样的xxxConfigurer,将Spring Security过滤器对应的配置类收集起来,并保存到父类AbstractConfiguredSecurityBuilder的configurers变量中。
在后续的构建过程中,再将这些xxxConfigurer构建为具体的Spring Security过滤器,并添加到HttpSecurity的filters对象中,部分代码如下
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder implements SecurityBuilder, HttpSecurityBuilder {
private final RequestMatcherConfigurer requestMatcherConfigurer;
private List filters = new ArrayList();
private RequestMatcher requestMatcher;
private FilterOrderRegistration filterOrders;
private AuthenticationManager authenticationManager;
//以form表单登陆配置为例(别的大部分方法都很相似),有两种重载方法可以进行配置,第一种是一个无参formLogin
//方法,该方法返回一个FormLoginConfigurer对象,开发者在该对象的基础上进行配置
public FormLoginConfigurer formLogin() throws Exception {
return (FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer());
}
//第二种是传入配置参数实例
public HttpSecurity formLogin(Customizer> formLoginCustomizer) throws Exception {
formLoginCustomizer.customize((FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer()));
return this;
}
//传入authenticationProvider,最后在beforeConfigure方法中触发AuthenticationManager对象构建
public HttpSecurity authenticationProvider(AuthenticationProvider authenticationProvider) {
getAuthenticationRegistry().authenticationProvider(authenticationProvider);
return this;
}
//构建DefaultSecurityFilterChain,在此之前会对filters进行排序
protected DefaultSecurityFilterChain performBuild() {
ExpressionUrlAuthorizationConfigurer> expressionConfigurer = getConfigurer(
ExpressionUrlAuthorizationConfigurer.class);
AuthorizeHttpRequestsConfigurer> httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class);
boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
this.filters.sort(OrderComparator.INSTANCE);
List sortedFilters = new ArrayList<>(this.filters.size());
for (Filter filter : this.filters) {
sortedFilters.add(((OrderedFilter) filter).filter);
}
return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
}
}
相比于HttpSecurity,WebSecurity在一个更大的层面上构建过滤器,WebSecurity负责将HttpSecurity所构建的DefaultSecurityFilterChain对象(可能有多个),以及其他一些需要忽略的请求,再次构建为一个FIlterChainProxy对象,同时添加上Http防火墙,部分核心代码如下:
public final class WebSecurity extends AbstractConfiguredSecurityBuilder implements SecurityBuilder, ApplicationContextAware, ServletContextAware {
private final List> securityFilterChainBuilders = new ArrayList<>();
//保存所有被忽略的请求,不会经过spring security过滤器链
private final List ignoredRequests = new ArrayList<>();
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder) {
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
//在此处构建所有的securityFilterChains,然后将其作为参数构建filterChainProxy
protected Filter performBuild() throws Exception {
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List securityFilterChains = new ArrayList<>(chainSize);
List>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
if (this.privilegeEvaluator == null) {
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
requestMatcherPrivilegeEvaluatorsEntries);
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (this.debugEnabled) {
result = new DebugFilter(filterChainProxy);
}
this.postBuildAction.run();
return result;
}
}
FilterChainProxy就是我们最终构建出来的过滤器链,通过spring提供的DelegatingFilterProxy将FilterChainProxy对象嵌入到Web Filter中(原生过滤器链)
如上图琐事,FilterChainProxy通过DelegatingFilterProxy代理过滤器被集成到Web Filter中,所以Spring Security中的最终执行的就是FilterChainProxy中的过滤器,部分代码如下:
public class FilterChainProxy extends GenericFilterBean {
private List filterChains;
private FilterChainValidator filterChainValidator = new NullFilterChainValidator();
public FilterChainProxy(SecurityFilterChain chain) {
this(Arrays.asList(chain));
}
public FilterChainProxy(List filterChains) {
this.filterChains = filterChains;
}
//doFilter方法相当于整个Spring Security过滤器链的入口
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (!clearContext) {
//进行实际的filter操作
doFilterInternal(request, response, chain);
return;
}
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
catch (RequestRejectedException ex) {
this.requestRejectedHandler.handle((HttpServletRequest) request, (HttpServletResponse) response, ex);
}
finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
}
在这两个方法中对SecurityBuilder进行初始化和配置
public interface SecurityConfigurer> {
void init(B builder) throws Exception;
void configure(B builder) throws Exception;
}