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.pswp.cn/diannao/42947.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42947.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42947.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sql注入問題批量處理

問題&#xff1a;SQL注入修改&#xff0c;歷史代碼全是${};無法修改的比如表名&#xff0c;列名&#xff0c;動態排序之類的不改&#xff0c;其他的都要修改完成 背景&#xff1a;新公司第一個任務就是SQL注入的修改&#xff0c;歷史sql全部都是${},一個個調整不太合適只能批量…

機場的出租車問題折線圖

分析并可視化機場離場車輛數數據 本文將詳細介紹如何使用Python的正則表達式庫re和繪圖庫matplotlib對機場離場車輛數數據進行分析和可視化。以下是具體步驟和代碼實現。 數據資源&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1rU-PRhrVSXq-8YdR6obc6Q?pwd1234 提…

Android C++系列:Linux常用函數和工具

1. 時間函數 1.1 文件訪問時間 #include <sys/types.h> #include <utime.h> int utime (const char *name, const struct utimebuf *t); 返回:若成功則為 0,若出錯則為- 1如果times是一個空指針,則存取時間和修改時間兩者都設置為當前時間; 如果times是非空指針…

一個python文件實現openai 轉換請求轉換成 ollama

最近在微軟開源了GraphRAG,項目&#xff0c;是一個很棒的項目&#xff0c;本著研究學習的態度下載了該項目測試&#xff0c;發現目前只可以使用openai chat gpt,或azure open chat gpt,也就是說意味著資料要上傳到第三方網站處理&#xff0c;為了本地的ollama也可以使用特意開發…

輪播圖案例

丐版輪播圖 <!DOCTYPE html> <html lang"zh-cn"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title> 基礎輪播圖 banner 移入移出</t…

6000字以上論文參考:基于Java+SpringMvc+Vue技術的實驗室管理系統設計與實現

可參考&#xff1a;基于JavaSpringMvcVue技術的實驗室管理系統設計與實現&#xff08;6000字以上論文參考&#xff09;-CSDN博客 論文參考&#xff1a;

【python】字典、列表、集合綜合練習

1、練習1(字典) 字典dic,dic {‘k1’:‘v1’, ‘k2’: ‘v2’, ‘k3’: [11,22,33]} (1). 請循環輸出所有的key dic {"k1": "v1", "k2": "v2", "k3": [11, 22, 33]} for k in dic.keys():print(k)k1 k2 k3(2). 請循環輸…

2024 WAIC|第四范式胡時偉分享通往AGI之路:行業大模型匯聚成海

7月4日&#xff0c;2024世界人工智能大會&#xff08;WAIC&#xff09;正式開幕。此次大會圍繞核心技術、智能終端、應用賦能等板塊展開&#xff0c;展覽規模、參展企業數均達歷史最高。第四范式受邀參展&#xff0c;集中展示公司十年來在行業大模型產業應用方面的實踐。在當天…

【知網CNKI-注冊安全分析報告】

前言 由于網站注冊入口容易被黑客攻擊&#xff0c;存在如下安全問題&#xff1a; 暴力破解密碼&#xff0c;造成用戶信息泄露短信盜刷的安全問題&#xff0c;影響業務及導致用戶投訴帶來經濟損失&#xff0c;尤其是后付費客戶&#xff0c;風險巨大&#xff0c;造成虧損無底洞…

dockerfile里的copy只能使用相對路徑嗎?

在 Dockerfile 中&#xff0c;COPY 指令既可以使用相對路徑&#xff0c;也可以使用絕對路徑&#xff08;但絕對路徑的使用方式和上下文有關&#xff09;。不過&#xff0c;在實踐中&#xff0c;你通常會看到使用相對路徑&#xff0c;因為 Dockerfile 的構建上下文&#xff08;b…

NewspaceGPT帶你玩系列之【Song Maker】

目錄 注冊一個賬號&#xff0c;用qq郵箱&#xff0c;然后登錄選一個可用的Plus&#xff0c;不要選3.5探索GPT今天的主角是【Song Maker】翻譯一下用漢語吧我寫詞。你譜曲和其他伴奏&#xff0c;例子&#xff1a; 搖滾&#xff0c;憂傷&#xff0c;吉他&#xff0c;鼓&#xff0…

聊一聊Oracle的空間計算函數SDO_NN

網上對這個函數介紹的很少&#xff0c;對使用上也很模糊&#xff0c;我來補充一下&#xff0c;讓大家了解一下這個函數 from test1 y, test2 p where SDO_NN(p.geom,y.geom,sdo_num_res1, 0.5 )TRUE; 上面這個表達式的含義也就是說在test2中找到一個距離test1很近的&#x…

Android約束布局的概念與屬性(1)

目錄 1&#xff0e;相對定位約束2&#xff0e;居中和偏移約束 約束布局&#xff08;ConstraintLayout&#xff09;是當前Android Studio默認的布局方式&#xff0c;也是最靈活的一種布局方式。約束布局推薦使用所見即所得的模式進行布局&#xff0c;約束布局的大部分布局可以通…

超詳細的 Linux 環境下 Anaconda 安裝與使用教程

超詳細的 Linux 環境下 Anaconda 安裝與使用教程 前言 在數據科學和機器學習領域&#xff0c;Anaconda 是一個非常受歡迎的發行版&#xff0c;提供了許多常用的包和工具。本文將詳細介紹如何在 Linux 系統上安裝和配置 Anaconda 環境&#xff0c;并展示如何高效地使用它。 一…

CentOS7下安裝Doris

Doris簡介 Apache Doris 是一款基于 MPP 架構的高性能、實時的分析型數據庫&#xff0c;以高效、簡單、統一的特點被人們所熟知&#xff0c;僅需亞秒級響應時間即可返回海量數據下的查詢結果&#xff0c;不僅可以支持高并發的點查詢場景&#xff0c;也能支持高吞吐的復雜分析場…

從0到1搭建個性化推送引擎:百數教學帶你掌握核心技術

百數低代碼的推送提醒功能允許用戶高度自定義提醒規則&#xff0c;支持多種提醒方式&#xff08;如釘釘、企業微信、微信、短信、語音、郵件等&#xff09;&#xff0c;以滿足不同場景下的需求。 通過預設字段和模板&#xff0c;用戶可以快速編輯提醒內容&#xff0c;減少重復…

BaseServlet的封裝

創建BaseServlet的必要性 如果不創建BaseServlet&#xff0c;現在我們只要實現一個功能&#xff0c;我們就需要創建一個servlet! 例如:用戶模塊(登錄&#xff0c;注冊&#xff0c;退出錄&#xff0c;激活&#xff0c;發送郵件等等功能) 也就是說&#xff0c;我們必須要創建一…

idea無法實力化id

解決&#xff1a;https://blog.csdn.net/qq_41264674/article/details/83409810?ops_request_misc&request_id&biz_id102&utm_termSerializable%E4%B8%8D%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E5%AE%9E%E5%8A%9B%E5%8C%96id&utm_mediumdistribute.pc_search_…

java-數據結構與算法-02-數據結構-03-遞歸

1. 概述 定義 計算機科學中&#xff0c;遞歸是一種解決計算問題的方法&#xff0c;其中解決方案取決于同一類問題的更小子集 In computer science, recursion is a method of solving a computational problem where the solution depends on solutions to smaller instances…

IT項目經理轉行大模型,項目經理的進來,你想知道的都在這里非常詳細

大模型&#xff08;如人工智能、機器學習和深度學習模型&#xff09;可以通過提供數據驅動的決策支持、自動化流程和預測分析來賦能IT項目經理。這些工具可以幫助項目經理更有效地管理項目&#xff0c;預測潛在的風險&#xff0c;并提高項目成功的可能性。以下是IT項目經理如何…