当前位置: 首页 > news >正文

SpringSecurity初始化过程

SpringSecurity初始化过程

SpringSecurity一定是被Spring加载的:

web.xml中通过ContextLoaderListener监听器实现初始化

<!--  初始化web容器--><!--设置配置文件的路径--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><!--配置Spring的监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

而spring配置文件中又引入了security的配置文件

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="com.shaoby.service"></context:component-scan><bean name="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>//引入security配置文件<import resource="spring-security.xml"/>
</beans>

所以看ContextLoaderListener是如何加载的

Spring容器初始化

ContextLoaderListener中的configureAndRefreshWebApplicationContext方法

   protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {String configLocationParam;if (ObjectUtils.identityToString(wac).equals(wac.getId())) {configLocationParam = sc.getInitParameter("contextId");if (configLocationParam != null) {wac.setId(configLocationParam);} else {wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));}}wac.setServletContext(sc);//读取配置文件configLocationParam = sc.getInitParameter("contextConfigLocation");if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}ConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);}this.customizeContext(sc, wac);//刷新容器,spring初始化的核心方法wac.refresh();}

refresh方法

    public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {this.prepareRefresh();//创建bean工厂ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

如何创建的bean工厂

spring通过loadBeanDefinitions方法完成初始化操作,它的实现方法可以通过xml配置文件或注解完成初始化

xml配置文件方法加载 XmlBeanDefinitionReader的loadBeanDefinitions方法中调用了doLoadBeanDefinitions方法
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {try {//通过流读取xml文件Document doc = this.doLoadDocument(inputSource, resource);//注册beanint count = this.registerBeanDefinitions(doc, resource);if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + count + " bean definitions from " + resource);}return count;} catch (BeanDefinitionStoreException var5) {throw var5;} catch (SAXParseException var6) {throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var6.getLineNumber() + " in XML document from " + resource + " is invalid", var6);} catch (SAXException var7) {throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var7);} catch (ParserConfigurationException var8) {throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var8);} catch (IOException var9) {throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var9);} catch (Throwable var10) {throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var10);}}
解析xml文件
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for(int i = 0; i < nl.getLength(); ++i) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element)node;if (delegate.isDefaultNamespace(ele)) {this.parseDefaultElement(ele, delegate);} else {//解析默认标签delegate.parseCustomElement(ele);}}}} else {//解析自定义标签delegate.parseCustomElement(root);}}private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {/如果是import标签,通过跟踪代码发现会去解析另一个配置文件,依次类推,直到没有import标签if (delegate.nodeNameEquals(ele, "import")) {this.importBeanDefinitionResource(ele);} else if (delegate.nodeNameEquals(ele, "alias")) {this.processAliasRegistration(ele);} else if (delegate.nodeNameEquals(ele, "bean")) {this.processBeanDefinition(ele, delegate);} else if (delegate.nodeNameEquals(ele, "beans")) {this.doRegisterBeanDefinitions(ele);}}

通过这段代码可以发现,spring会先解析默认标签,因此会先执行springsecurity的配置文件引入的操作

解析自定义标签
    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {//获取标签String namespaceUri = this.getNamespaceURI(ele);if (namespaceUri == null) {return null;} else {//解析自定义标签,获得能解析该标签的HandlerResolver解析器NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;} else {return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}}}

springSecurity解析器SecurityNamespaceHandler

/**不同的标签交给不同的解析器去解析*/private void loadParsers() {this.parsers.put("ldap-authentication-provider", new LdapProviderBeanDefinitionParser());this.parsers.put("ldap-server", new LdapServerBeanDefinitionParser());this.parsers.put("ldap-user-service", new LdapUserServiceBeanDefinitionParser());this.parsers.put("user-service", new UserServiceBeanDefinitionParser());this.parsers.put("jdbc-user-service", new JdbcUserServiceBeanDefinitionParser());this.parsers.put("authentication-provider", new AuthenticationProviderBeanDefinitionParser());this.parsers.put("global-method-security", new GlobalMethodSecurityBeanDefinitionParser());this.parsers.put("authentication-manager", new AuthenticationManagerBeanDefinitionParser());this.parsers.put("method-security-metadata-source", new MethodSecurityMetadataSourceBeanDefinitionParser());if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", this.getClass().getClassLoader())) {this.parsers.put("debug", new DebugBeanDefinitionParser());this.parsers.put("http", new HttpSecurityBeanDefinitionParser());this.parsers.put("http-firewall", new HttpFirewallBeanDefinitionParser());this.parsers.put("filter-security-metadata-source", new FilterInvocationSecurityMetadataSourceParser());this.parsers.put("filter-chain", new FilterChainBeanDefinitionParser());this.filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();this.parsers.put("client-registrations", new ClientRegistrationsBeanDefinitionParser());}if (ClassUtils.isPresent("org.springframework.messaging.Message", this.getClass().getClassLoader())) {this.parsers.put("websocket-message-broker", new WebSocketMessageBrokerSecurityBeanDefinitionParser());}}

http标签的解析,HttpSecurityBeanDefinitionParser

    public BeanDefinition parse(Element element, ParserContext pc) {CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));pc.pushContainingComponent(compositeDef);//注册FilterChainProxyregisterFilterChainProxyIfNecessary(pc, pc.extractSource(element));//拿到FilterChainProxyBeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition("org.springframework.security.filterChains");List<BeanReference> filterChains = (List)listFactoryBean.getPropertyValues().getPropertyValue("sourceList").getValue();//将过滤器放到filterChains中filterChains.add(this.createFilterChain(element, pc));pc.popAndRegisterContainingComponent();return null;}private BeanReference createFilterChain(Element element, ParserContext pc) {boolean secured = !"none".equals(element.getAttribute("security"));if (!secured) {if (!StringUtils.hasText(element.getAttribute("pattern")) && !StringUtils.hasText("request-matcher-ref")) {pc.getReaderContext().error("The 'security' attribute must be used in combination with the 'pattern' or 'request-matcher-ref' attributes.", pc.extractSource(element));}for(int n = 0; n < element.getChildNodes().getLength(); ++n) {if (element.getChildNodes().item(n) instanceof Element) {pc.getReaderContext().error("If you are using <http> to define an unsecured pattern, it cannot contain child elements.", pc.extractSource(element));}}return this.createSecurityFilterChainBean(element, pc, Collections.emptyList());} else {BeanReference portMapper = this.createPortMapper(element, pc);BeanReference portResolver = this.createPortResolver(portMapper, pc);ManagedList<BeanReference> authenticationProviders = new ManagedList();BeanReference authenticationManager = this.createAuthenticationManager(element, pc, authenticationProviders);boolean forceAutoConfig = isDefaultHttpConfig(element);HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, forceAutoConfig, pc, portMapper, portResolver, authenticationManager);AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager, httpBldr.getSessionStrategy(), portMapper, portResolver, httpBldr.getCsrfLogoutHandler());httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());httpBldr.setEntryPoint(authBldr.getEntryPointBean());httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());httpBldr.setCsrfIgnoreRequestMatchers(authBldr.getCsrfIgnoreRequestMatchers());authenticationProviders.addAll(authBldr.getProviders());List<OrderDecorator> unorderedFilterChain = new ArrayList();unorderedFilterChain.addAll(httpBldr.getFilters());unorderedFilterChain.addAll(authBldr.getFilters());unorderedFilterChain.addAll(this.buildCustomFilterList(element, pc));unorderedFilterChain.sort(new OrderComparator());this.checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));List<BeanMetadataElement> filterChain = new ManagedList();Iterator var13 = unorderedFilterChain.iterator();while(var13.hasNext()) {OrderDecorator od = (OrderDecorator)var13.next();filterChain.add(od.bean);}return this.createSecurityFilterChainBean(element, pc, filterChain);}}
//注册FilterChainProxy
static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {if (!pc.getRegistry().containsBeanDefinition("org.springframework.security.filterChainProxy")) {BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean, "org.springframework.security.filterChains"));BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);fcpBldr.getRawBeanDefinition().setSource(source);fcpBldr.addConstructorArgReference("org.springframework.security.filterChains");fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));BeanDefinition fcpBean = fcpBldr.getBeanDefinition();pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, "org.springframework.security.filterChainProxy"));//添加别名springSecurityFilterChainpc.getRegistry().registerAlias("org.springframework.security.filterChainProxy", "springSecurityFilterChain");}}

到这可以看到所有的过滤器被放到filterChain中

http://www.lryc.cn/news/394014.html

相关文章:

  • Python爬取股票信息-并进行数据可视化分析,绘股票成交量柱状图
  • 秋招突击——7/4——复习{}——新作{最长公共子序列、编辑距离、买股票最佳时机、跳跃游戏}
  • udp发送数据如果超过1个mtu时,抓包所遇到的问题记录说明
  • 电子电气架构 --- 智能座舱万物互联
  • 笔记本电脑内存不够
  • Vue项目使用mockjs模拟后端接口
  • Linux下使用arping检测IP地址是否冲突
  • 为什么 npm run serve 正常,npm run build 就报错:digital envelope routines::unsupported
  • 模电基础 - 简介
  • uniapp中实现瀑布流 短视频页面展示
  • python-开关灯(赛氪OJ)
  • 基于改进高斯-拉普拉斯滤波器的一维时间序列平滑与降噪(MATLAB)
  • 计算组的妙用!!页面权限控制
  • Self-Instruct构造Prompt的例子
  • 友好前端vue脚手架
  • SQL Server特性
  • 华为HCIP Datacom H12-821 卷25
  • 如何在 Selenium Python 中解决验证码 | 2024 完整指南
  • ASCII码对照表【2024年汇总】
  • 刷题之买股票的最佳时机(leetcode)
  • Apache Seata透过源码解决SeataAT模式整合Mybatis-Plus失去MP特性的问题
  • 1.2 如何让机器说人话?万字长文回顾自然语言处理(NLP)的前世今生 —— 《带你自学大语言模型》系列
  • 【QT】按钮类控件
  • RedHat运维-Linux软件包管理基础-RHEL9软件包管理基础
  • uniapp----- 判断小程序版本有没有更新
  • Spring Boot的无缝衔接:深入解析与实践
  • 在Linux上查找文件的2个好用的命令
  • 实现WebSocket聊天室功能
  • qt opencv 应用举例
  • QT5.12环境搭建与源码编译