Spring Security 源码学习(二): Spring Security自动配置(初始化流程)
【深度好文】: 「和耳朵」SpringSecurity是如何代理过滤器链的?
1. 自动配置security的bean信息
下面是 Spring Boot autoconfigure 自动创建的配置类信息
2. springSecurityFilterChain 初始化
1. springSecurityFilterChain 定义
WebSecurityConfiguration中定义了 springSecurityFilterChain 这个bean
@Configuration(proxyBeanMethods = false) public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware { @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain() throws Exception { boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty(); if (!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); } return webSecurity.build(); } }
2. springSecurityFilterChain 初始化
待补充
3. springSecurityFilterChain 如何被添加到Filter
创建一个 targetBeanName 属性值为 springSecurityFilterChain 的 DelegatingFilterProxy Filter 实例, 并注册到 ServletContext
1. AbstractSecurityWebApplicationInitializer
public abstract class AbstractSecurityWebApplicationInitializer implements WebApplicationInitializer { public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain"; public final void onStartup(ServletContext servletContext) { beforeSpringSecurityFilterChain(servletContext); if (this.configurationClasses != null) { AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); rootAppContext.register(this.configurationClasses); servletContext.addListener(new ContextLoaderListener(rootAppContext)); } if (enableHttpSessionEventPublisher()) { servletContext.addListener( "org.springframework.security.web.session.HttpSessionEventPublisher"); } servletContext.setSessionTrackingModes(getSessionTrackingModes()); insertSpringSecurityFilterChain(servletContext); afterSpringSecurityFilterChain(servletContext); } /** * 创建一个 DelegatingFilterProxy 实例注册 Filter */ private void insertSpringSecurityFilterChain(ServletContext servletContext) { String filterName = DEFAULT_FILTER_NAME; DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy( filterName); String contextAttribute = getWebApplicationContextAttribute(); if (contextAttribute != null) { springSecurityFilterChain.setContextAttribute(contextAttribute); } registerFilter(servletContext, true, filterName, springSecurityFilterChain); } /** * 将 DelegatingFilterProxy 添加到 ServletContext 的 Filter中 */ private void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) { Dynamic registration = servletContext.addFilter(filterName, filter); if (registration == null) { throw new IllegalStateException( "Duplicate Filter registration for '" + filterName + "'. Check to ensure the Filter is only configured once."); } registration.setAsyncSupported(isAsyncSecuritySupported()); EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes(); registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, "/*"); } }
4. springSecurityFilterChain 如何工作
DelegatingFilterProxy 在请求第一次到来时初始化, 从应用中获取bean名称为 springSecurityFilterChain 的实例, 然后调用 springSecurityFilterChain 的 doFilter 方法
public class DelegatingFilterProxy extends GenericFilterBean { @Nullable private String targetBeanName; @Nullable private volatile Filter delegate; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 懒加载,使用时进行初始化 Filter delegateToUse = this.delegate; if (delegateToUse == null) { // 初始化 delegate synchronized (this.delegateMonitor) { delegateToUse = this.delegate; if (delegateToUse == null) { WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: " + "no ContextLoaderListener or DispatcherServlet registered?"); } delegateToUse = initDelegate(wac); } this.delegate = delegateToUse; } } // 调用 springSecurityFilterChain 的 doFilter() invokeDelegate(delegateToUse, request, response, filterChain); } protected Filter initDelegate(WebApplicationContext wac) throws ServletException { String targetBeanName = getTargetBeanName(); Assert.state(targetBeanName != null, "No target bean name set"); // 根据 bean 名称获取实例对象 Filter delegate = wac.getBean(targetBeanName, Filter.class); if (isTargetFilterLifecycle()) { delegate.init(getFilterConfig()); } return delegate; } }
如果文章对您有所帮助,可以点一下推荐
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
2020-05-18 go:基本数据类型
2020-05-18 shell 实现懒惰匹配或最小匹配