Spring security 之 tomcat到springSecurityFilterChain拦截器过程分析(三)

1.前景提要

springSecurityFilterChain是一个DelegatingFilterProxyRegistrationBean的对象。
感谢青稚774 老哥的指正。
springSecurityFilterChain是先通过spring的autoconfiguration注入spring容器中,然后被DelegatingFilterProxyRegistrationBean注入到servlet容器中。
所以说 【springSecurityFilterChain是一个DelegatingFilterProxyRegistrationBean`的对象】 这句话是错的。
springSecurityFilterChain是DelegatingFilterProxyRegistrationBean注册目标,将它注册到servlet容器中。

在第二篇中,我们分析得知,spring security通过注入DelegatingFilterProxyRegistrationBean对象到spring 容器中来使 servlet 容器在初始化的过程中能够获取并初始化到自己的过滤器链中去。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hzHJZOt-1625467543987)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9325653b-3f07-4666-a4f0-0e8b4da8b59e/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sMcy44vf-1625467543991)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/50a2db35-3807-426f-82b5-3c921f866f41/Untitled.png)]



2.加入servlet 容器拦截器链中的springSecurityFilterChain如何运作

这里先从tomcat拦截器链开始,tomcat是接受请求的容器,由它负责处理请求并转到对应的应用中去。

大致流程:

  1. Socket监听
  2. Protocol协议解析
  3. CoyoteAdapter 将解析出的数据转为Request和Response(也就是适配为同样格式数据)
  4. Engine 开始根据请求选择对应的Host应用程序来处理这个请求
  5. 每个Host根据对应的URL来选择Context
  6. 每个Context包含一个对应的servlet包装类(Wrapper),在springmvc中,tomcat的Wrapper包含的就是DispatcherServlet
  7. 在这个Wrapper中会创建一个ApplicationFilterChain,这个拦截器链就是从servlet容器中获取的
  8. 这个拦截器链中就包含前面设置进去的springSecurityFilterChain

上面就是从tomcat 到 springSecurityFilterChain的大致流程。



3. ApplicationFilterChain之tomcat拦截器链的构建过程

1.基于ApplicationFilterFactory创建拦截器链
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xUQTaE09-1625467543993)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7ff952aa-65e9-48de-9756-df9b58428cce/Untitled.png)]

2.从StandardContext中获取拦截器数组

在这里插入图片描述

3.添加拦截器到ApplicationFilterChain
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uQPD1d63-1625467543999)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/77e7a934-af25-4999-a172-7a405689d948/Untitled.png)]

但是这里估计有人会有点疑问,spring 明明是将filter设置到ServletContext,怎么tomcat 获取拦截器的时候,是从StandardContext中获取的呢?



4.ServletContext 将 filter 注入到StandardContext

ServletContext是一个接口,其默认实现为ApplicationContext

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nqhYpAfS-1625467544001)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/00ea63f7-7ac3-4154-8b55-6deadf59aca9/Untitled.png)]

ApplicationContext是持有StandardContext

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MVAh1ha1-1625467544003)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e19ee77f-71df-4027-8001-a9cf15beb97d/Untitled.png)]

这个时候就需要看看addFilter方法了,这个是我们将filter添加到servletContext的方法。

private FilterRegistration.Dynamic addFilter(String filterName,
            String filterClass, Filter filter) throws IllegalStateException {
		
        if (filterName == null || filterName.equals("")) {
            throw new IllegalArgumentException(sm.getString(
                    "applicationContext.invalidFilterName", filterName));
        }

        if (!context.getState().equals(LifecycleState.STARTING_PREP)) {
            //TODO Spec breaking enhancement to ignore this restriction
            throw new IllegalStateException(
                    sm.getString("applicationContext.addFilter.ise",
                            getContextPath()));
        }
				// 可以看到是从StandardContext获取FilterDef
        FilterDef filterDef = context.findFilterDef(filterName);

        // Assume a 'complete' FilterRegistration is one that has a class and
        // a name
        if (filterDef == null) {
            filterDef = new FilterDef();
            filterDef.setFilterName(filterName);
						// 添加filter 也是添加到StandardContext
            context.addFilterDef(filterDef);
        } else {
            if (filterDef.getFilterName() != null &&
                    filterDef.getFilterClass() != null) {
                return null;
            }
        }

        if (filter == null) {
            filterDef.setFilterClass(filterClass);
        } else {
            filterDef.setFilterClass(filter.getClass().getName());
            filterDef.setFilter(filter);
        }

        return new ApplicationFilterRegistration(filterDef, context);
    }

从上面可以看到其实ServletContext的filter信息,其实是放在StandardContext中进行存储的。

所以也就是为啥能通过StandardContext获取filter数组了。



5.小结

整个过程其实就是创建ApplicationFilterChain,然后从servletContext中获取过滤器数组加入到拦截器链中。

一张图小结一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwT577pS-1625467544004)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4e67f400-ddab-4a95-a1e1-fd11315c4153/05_tomcatApplicationFilterChainsecurityFilterChain.png)]

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欢谷悠扬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值