Spring Security3源码分析-http标签解析(转)

为什么80%的码农都做不了架构师?>>>   hot3.png

在FilterChainProxy初始化的过程中,大概描述了标签解析的一些步骤,但不够详细
  <http auto-config="true">
    <remember-me key="workweb" token-validity-seconds="3600" data-source-ref="dataSource"/>
    <form-login login-page="/login.jsp"/>
    <logout logout-success-url="/login.jsp"/>
    <intercept-url pattern="/*" access="ROLE_USER"/>
  </http>

http标签的解析过程由类org.springframework.security.config.http.HttpSecurityBeanDefinitionParser解析。
public BeanDefinition parse(Element element, ParserContext pc) {
        CompositeComponentDefinition compositeDef =
            new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
        pc.pushContainingComponent(compositeDef);
        final Object source = pc.extractSource(element);
        //portMapperName、matcher主要提供给SSL相关类使用
        final String portMapperName = createPortMapper(element, pc);
        final UrlMatcher matcher = createUrlMatcher(element);
        //http标签构造器,该构造函数中对intercept-url、create-session子标签
         //进行了预处理,并将所有的intercept-url信息放到List中。
        HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);
        //处理List中的intercept-url信息(如pattern、filters),并将结果放到
         //Map集合filterChainMap中
        httpBldr.parseInterceptUrlsForEmptyFilterChains();
        //创建过滤器SecurityContextPersistenceFilter
        httpBldr.createSecurityContextPersistenceFilter();
        //创建过滤器SessionManagementFilter
        httpBldr.createSessionManagementFilters();
        //新建一个空的provider集合
        ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
        //通过空的provider集合产生一个ProviderManager的bean定义
        BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);
        //创建过滤器SecurityContextHolderAwareRequestFilter
        httpBldr.createServletApiFilter();
        //判断intercept-url标签是否有requires-channel属性,如果有,则创建过滤器
         //ChannelProcessingFilter
        httpBldr.createChannelProcessingFilter();
        //创建过滤器FilterSecurityInterceptor
        //这个创建过程比较复杂,分别为:
         //1.需要判断是否使用表达式use-expressions
        //2.解析intercept-url中的access等属性
         //3.RoleVoter、AffirmativeBased的定义…………
        httpBldr.createFilterSecurityInterceptor(authenticationManager);
        //下面是与认证有关的过滤器,HttpConfigurationBuilder,
         //AuthenticationConfigBuilder将解析的职责进行了分离
        AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
                httpBldr.isAllowSessionCreation(), portMapperName);
        //创建过滤器AnonymousAuthenticationFilter,并且构造了provider:
         //AnonymousAuthenticationProvider,供ProviderManager使用
        authBldr.createAnonymousFilter();
        //判断是否有remember-me标签,如果有,则创建过滤器
         //RememberMeAuthenticationFilter,并且构造了provider:
         //RememberMeAuthenticationProvider供ProviderManager使用
        authBldr.createRememberMeFilter(authenticationManager);
        //判断是否有request-cache标签,如果有,则构造ref指明的bean定义
         //如果没有,则构造HttpSessionRequestCache缓存
        authBldr.createRequestCache();
        //创建过滤器BasicAuthenticationFilter
        authBldr.createBasicFilter(authenticationManager);
        //创建LoginUrlAuthenticationEntryPoint,以及创建过滤器
         //UsernamePasswordAuthenticationFilter
        authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
        //判断是否使用了openid-login,如果有,则构造openId客户端
         //org.springframework.security.openid.OpenID4JavaConsumer
        authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
        //判断是否使用了x509,如果有,则创建过滤器
         //X509AuthenticationFilter
        authBldr.createX509Filter(authenticationManager);
        //判断是否配置了logout,如果有,则创建过滤器LogoutFilter
        authBldr.createLogoutFilter();
        //判断是否配置login-page属性,如果没有,则创建过滤器
         //DefaultLoginPageGeneratingFilter,生成默认登录页面
        authBldr.createLoginPageFilterIfNeeded();
        //创建UserDetailsServiceInjectionBeanPostProcessor
        //动态向x509、openID、rememberme服务注入UserDetailsService
         //主要使用了spring的BeanPostProcessor接口功能
        authBldr.createUserServiceInjector();
        //创建过滤器ExceptionTranslationFilter
        authBldr.createExceptionTranslationFilter();

        List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
        //向FilterChain链中添加filters
        unorderedFilterChain.addAll(httpBldr.getFilters());
        unorderedFilterChain.addAll(authBldr.getFilters());
        //向ProviderManager中添加provider
        authenticationProviders.addAll(authBldr.getProviders());

        BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
        requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());
        unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
        //添加自定义的Filter,也就是custom-filter标签定义的Filter
        unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
        //对FilterChian链中的Filter进行排序,排序规则参见SecurityFilters枚举类
        Collections.sort(unorderedFilterChain, new OrderComparator());
        checkFilterChainOrder(unorderedFilterChain, pc, source);

        List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();

        for (OrderDecorator od : unorderedFilterChain) {
            filterChain.add(od.bean);
        }

        ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
        BeanDefinition universalMatch = new RootBeanDefinition(String.class);
        universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());
        filterChainMap.put(universalMatch, filterChain);
        //构造FilterChainProxy的Bean
        registerFilterChainProxy(pc, filterChainMap, matcher, source);

        pc.popAndRegisterContainingComponent();
        return null;
    }

至此,大概http标签的解析已经差不多了,虽然每个Filter的BeanDefinition创建过程还没有一一细说,但基本步骤如下:

1.通过Filter的类路径获取BeanDefinitionBuilder对象,如
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);

2.解析xml标签属性,再通过BeanDefinitionBuilder的addPropertyValue、addPropertyReference等方法设置Filter对应BeanDefinition的属性值、依赖bean

3.注册BeanDefinition。通过
ParserContext.registerBeanComponent(
new BeanComponentDefinition(BeanDefinition,beanId));
完成bean的注册。还可以通过ParserContext.getRegistry().registerAlias
方法注册bean的别名

实际上,标签解析就是构造BeanDefinition,然后注册到bean factory中。而BeanDefinition就是Spring中定义bean的数据结构。

转载于:https://my.oschina.net/blooms/blog/79106

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295049.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android之React Native 中组件的生命周期

React Native 中组件的生命周期 概述 就像 Android 开发中的 View 一样&#xff0c;React Native&#xff08;RN&#xff09; 中的组件也有生命周期&#xff08;Lifecycle&#xff09;。所谓生命周期&#xff0c;就是一个对象从开始生成到最后消亡所经历的状态&#xff0c;理解…

当女朋友学会「监视」男朋友......

1 日本网友拍到两只水母互殴&#xff01;▼2 打印机也会生气&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 现在你们可以互换卡槽了~&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 有什么适合整蛊朋友的恶作剧▼5 哈哈哈哈哈&#xff…

使用.NET5、Blazor和Electron.NET构建跨平台桌面应用

Electron.NET是一个嵌入了ASP.NET Core的Electron的封装&#xff0c;通过Electron.NET可以构建基于.NET5的跨平台的桌面应用&#xff0c;使得开发人员只需要使用ASP.NET Core和 Blazor就可以胜任桌面应用的开发工作。开发环境操作系统Windows/macOS/Linux.NET5.0npm创建新项目创…

linux内核分析作业3:跟踪分析Linux内核的启动过程

内核源码目录 1、 arch:录下x86重点关注 2、 init&#xff1a;目录下main.c中的start_kernel是启动内核的起点 3、 ipc&#xff1a;进程间通信的目录 实验 使用实验楼的虚拟机打开shell cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 使…

linux安装定制添加输入,Arch Linux--定制自己的Linux操作系統(乙-國際化桌面安裝篇)...

Arch Linux&#xff0d;&#xff0d;定制自己的Linux操作系統&#xff0d;&#xff0d;&#xff0d;&#xff0d;乙&#xff0d;國際化&桌面安裝篇相信大家看了《甲-安裝篇》之後&#xff0c;Arch Linux系統已經可以正常運行了吧&#xff1f;不過&#xff0c;Arch Linux默認…

这几部经典纪录片,竟然还有人没看过?

全世界只有3.14 % 的人关注了爆炸吧知识看纪录片&#xff0c;既可以追溯上下数千年的历史文化&#xff0c;也可以欣赏从宇宙到地心深处的奇妙境界&#xff0c;而及其超级精彩的画面即使定格&#xff0c;也是一幅摄影佳作。纪录片题材广泛、制作精良&#xff0c;观看起来算的上是…

github 上微信判断是否被删除的源码 以及使用解惑

为什么80%的码农都做不了架构师&#xff1f;>>> 从Github上的https://github.com/0x5e/wechat-deleted-friends&#xff0d;&#xff0d;clone出来的代码 今天在我的机器上不能运行了&#xff0c;环境为Mac 10.10 python2.7.10中 提示错误&#xff0c; Traceback (…

坑爹!千万不要在生产环境使用控制台日志

前言某控制台应用程序会随机卡死&#xff0c;一直找不到原因。无意中在控制台敲了下回车&#xff0c;发现程序居然恢复正常了。最后在stackoverflow上找到了这个帖子&#xff1a;How and why does QuickEdit mode in Command Prompt freeze applications?[1]原来是“快速编辑模…

这五部关于海洋的纪录片,每一帧都犹如壁纸!

全世界只有3.14 % 的人关注了爆炸吧知识虽说读万卷书不如行万里路&#xff0c;但现在足不出户也能让你见识到世界各地的奇特风景。今天小编要推荐几部关于海洋的纪录片&#xff0c;这些纪录片从不同方面揭示了深海下面的奥秘&#xff0c;带你领略不一样的神秘景色。&#xff08…

UML类图几种关系的总结

在UML类图中&#xff0c;常见的有以下几种关系:泛化&#xff08;Generalization&#xff09;, 实现&#xff08;Realization&#xff09;,关联&#xff08;Association&#xff09;,聚合&#xff08;Aggregation&#xff09;,组合(Composition)&#xff0c;依赖(Dependency) 1…

Ruby:字符集和编码学习总结

背景 Ruby直到1.9版本才很好的支持了多字节编码&#xff0c;本文简单总结了今天学习的关于Ruby编码方面的知识。 字符串可以使用不同的编码 在.NET中字符串的编码是一致的&#xff0c;Ruby允许字符串有不同的编码&#xff0c;当时我就在想&#xff1a;如果两个不同编码的字符串…

Redis持久化RDB和AOF区别

RDBRDB是Redis内存到硬盘的快照&#xff0c;用于redis持久化&#xff0c;创建RDB二进制文件&#xff0c;将存储在内存中的数据&#xff0c;持久化的放到硬盘中&#xff0c;当我们需要这些数据的时候&#xff0c;启动载入RDB文件&#xff0c;数据将会被存入内存中&#xff0c;其…

央视力荐的这套书,让5岁孩子看漫画,秒懂物理,学习早“开窍”!

▲ 点击查看今年的高考&#xff0c;不得不说&#xff0c;一度被浙江学霸刷屏&#xff01;他总分720分&#xff0c;物理等3门满分的成绩&#xff0c;最终获得“浙江高考状元”。状元能摘得桂冠&#xff0c;除了日积月累的不断努力外&#xff0c;最重要的是&#xff0c;不断调整自…

MongoDB基本操作(增删改查)

2019独角兽企业重金招聘Python工程师标准>>> 基本操作 基本的“增删查改“&#xff0c;在DOS环境下输入mongo命令打开shell&#xff0c;其实这个shell就是mongodb的客户端&#xff0c;同时也是一个js的编译器&#xff0c;默认连接的是“test”数据库。 【出错】 首先…

Kubernetes + .NET Core 的落地实践

1容器化背景本来生活网&#xff08;benlai.com&#xff09;是一家生鲜电商平台&#xff0c;公司很早就停止了烧钱模式&#xff0c;开始追求盈利。既然要把利润最大化&#xff0c;那就要开源节流&#xff0c;作为技术可以在省钱的方面想想办法。我们的生产环境是由 IDC 机房的 1…

传说中的宇宙最水诺奖得主:本科历史学,却凭借“一纸”博士论文摘取诺贝尔物理学奖,出道即巅峰!...

全世界只有3.14 % 的人关注了爆炸吧知识他&#xff0c;到底是不是最水的诺奖得主&#xff1f;超模君曾经介绍了学历史&#xff0c;最终成为数学、物理大牛的威滕&#xff08;传送门&#xff09;&#xff0c;然而竟出现了德布罗意姥爷的高分点赞&#xff01;那今天&#xff0c;超…

基于事件驱动架构构建微服务第13部分:使用来自Apache KAFKA的事件并将投影流传输到ElasticSearch...

原文链接&#xff1a;https://logcorner.com/building-microservices-through-event-driven-architecture-part13-read-model-projection-project-streams-into-elasticsearch/在本教程中&#xff0c;我将展示如何从KAFKA读取流并将流投影到ElasticSearch中。我必须使用来自KAF…

惊呆了!这篇论文全文都是脏话,可编辑部居然对它评价极佳并发表了!

全世界只有3.14 % 的人关注了爆炸吧知识本文转自&#xff1a;募格学术你见过最奇奇怪怪的论文是什么&#xff1f;一教授为了抗议三流科学杂志发送垃圾邮件&#xff0c;回复了一篇全文只重复七个脏话字眼的论文&#xff0c;可没想到的是&#xff0c;它竟然还被 出&#xff01;版…

单IP无TMG拓扑Lync Server 2013:前端服务器

在前面的基础架构和活动目录两篇文章中&#xff0c;我们已经准备好了Lync Server的所有环境。其实今天虽然部署的是Lync Server 2013的Preview版&#xff0c;但实际上与我们部署Lync的步骤以及规范是完全一样的&#xff0c;所以大家完全可以抛开Lync Server 2013 Preview版本本…

MySQL学习笔记之五:存储引擎和查询缓存

一、存储引擎1、InnoDB⑴InnoDB是基于聚簇索引建立的&#xff0c;基于主键索引查询时&#xff0c;性能较好&#xff1b;它的辅助索引中必须包含主键列&#xff1b;因此&#xff0c;若表上的索引较多&#xff0c;为节约空间&#xff0c;主键应尽可能小⑵InnoDB支持自适应hash索引…