Spring Security原理篇(四) FilterChainProxy

在前面的三篇文章中,已经大概交代了一下三个地方

  • spring security启动WebSecurityConfiguration主要做了两件事情:
    1.根据WebSecurityConfigurerAdapter中配置的信息创建WebSecurity这个类
    2.springSecurityFilterChain()创建了一个名叫springSecurityFilterChain的过滤器,然后值得一提的是在调用WebSecuritybuild()创建过滤器的时候,调用到了WebSecurityinit()方法创建了一个HttpSecurity的对象,这里会根据配置为我们创建过滤器,最后添加到DefaultSecurityFilterChain过滤器链里面来
    Spring Security(一) 启动原理

  • spring security 后面讲到过滤器创建的过程,其实主要是过滤器链,比如ignoreRequests是怎样创建过滤器的
    Spring Security(二) 过滤器原理

  • 后面我们讲到一个非常重要的类HttpSecurity讲到,其中重点通过formLogin()这个方法通过源码看了一下怎样通过对HttpSecurity的配置最后转换到Filter。以及怎样直接通过addFilterXXX来添加一个过滤器
    Spring Security(三) HttpSecurity

  • 然后我们到此为止,还是没有弄懂过滤器最终的结构,以及在零散的源代码阅读背后,还差一个关于过滤器的总体的把握。

1.为什么要说这个类

在前面的文章中我们已经说到所有的过滤器链都添加到了securityFilterChains这个列表中,后面出现了下面一行代码

FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);

我们知道FilterChainProxy的bean的名字叫做springSecurityFilterChain里面包含了我们的过滤器链
所以我们必须要清楚他的工作原理

2.类的简单说明

2.1变量

2.1.1 filterChains

变量定义

private List<SecurityFilterChain> filterChains
  • 里面存储了过滤器链的信息

2.2构造函数

public FilterChainProxy(List<SecurityFilterChain> filterChains) {
        this.filterChains = filterChains;
    }

WebSecurityperformBuild()方法中我们对于spring security的配置最后生成的过滤器链设置到filterChains 这个变量中

3.虚拟过滤器链VirtualFilterChain

private static class VirtualFilterChain implements FilterChain {
                 
                //原始过滤器链,代表了spring 的application context中所有的过滤器连
               //其实可以参考DelegatingFilterProxy
        private final FilterChain originalChain;
               
                //spring security的过滤器链
        private final List<Filter> additionalFilters;
                
               //因为在FilterChainProxy中request和response被封装到HttpFirewall中,所以我们从这里获取请求信息
        private final FirewalledRequest firewalledRequest;
        
             //spring security的过滤器的长度
              private final int size;
            
           //当前执行到的位置
        private int currentPosition = 0;

        private VirtualFilterChain(FirewalledRequest firewalledRequest,
                FilterChain chain, List<Filter> additionalFilters) {
            this.originalChain = chain;
            this.additionalFilters = additionalFilters;
            this.size = additionalFilters.size();
            this.firewalledRequest = firewalledRequest;
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response)
                throws IOException, ServletException {
                        //表示spring security的过滤器全部执行完成,那么可以执行spring的application context 中的其他的过滤器链了
            if (currentPosition == size) {
                if (logger.isDebugEnabled()) {
                    logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
                            + " reached end of additional filter chain; proceeding with original chain");
                }

                // Deactivate path stripping as we exit the security filter chain
                this.firewalledRequest.reset();

                originalChain.doFilter(request, response);
            }
            else {
                               //获取当前过滤器执行到的为止
                currentPosition++;
                               
                               //当前需要执行的过滤器
                Filter nextFilter = additionalFilters.get(currentPosition - 1);

                if (logger.isDebugEnabled()) {
                    logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
                            + " at position " + currentPosition + " of " + size
                            + " in additional filter chain; firing Filter: '"
                            + nextFilter.getClass().getSimpleName() + "'");
                }

                               //执行当前的过滤器
                nextFilter.doFilter(request, response, this);
            }
        }
    }

4 FilterChainProxydoFilter方法

我们知道FilterChainProxy已经被注册到application context中,那么就会被DelegatingFilterProxy执行到自己的doFilter()方法,然而先没必要想这么多,就把FilterChainProxy当成我们在web.xml中定义的一个Filter就行,当有请求进来就会去执行doFilter方法

@Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
           //只是一个存储信息或者说是否已经在执行的标志
        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
        if (clearContext) {
            try {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
                doFilterInternal(request, response, chain);
            }
            finally {
                SecurityContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        }
        else {
            doFilterInternal(request, response, chain);
        }
    }

    private void doFilterInternal(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        FirewalledRequest fwRequest = firewall
                .getFirewalledRequest((HttpServletRequest) request);
        HttpServletResponse fwResponse = firewall
                .getFirewalledResponse((HttpServletResponse) response);

        List<Filter> filters = getFilters(fwRequest);

        if (filters == null || filters.size() == 0) {
            if (logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(fwRequest)
                        + (filters == null ? " has no matching filters"
                                : " has an empty filter list"));
            }

            fwRequest.reset();

            chain.doFilter(fwRequest, fwResponse);

            return;
        }
               VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
        vfc.doFilter(fwRequest, fwResponse);
    }
  • 上面这么多行的代码其实我们大概捋顺一下就知道,主要的无非就是当有请求,判断当前过滤器列表里面是否有过滤器,如果没有执行spring application context中的其他的过滤器链,如果有执行一下两行代码
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
  • 首先新建了一个虚拟过滤器链,请参考上面的代码
  • 其次执行了doFilter()方法
  • 根据上面对于VirtualFilterChain的源代码注释,我们是可以看到过滤器链是怎样被执行完的。

5.总结

这个类还是比较简单和清晰明了的。没有晦涩的继承关系。到此为止,我们已经了解到了spring security 的一个请求过来为什么会去穿透我们的过滤器,可以说对于spring security的启动,spring security filter chain的组建,我们基本已经了解完成,最后,在默认情况下进行调试,我们看一下我们的默认的过滤器有哪些,也顺便结束这篇文章吧.

默认配置下的过滤器
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,678评论 6 342
  • 前言 最近在弄微信的OAuth认证,我们认证服务及作为客户端又作为认证服务端。因此需要对spring cloud ...
    不小下阅读 11,914评论 3 54
  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,226评论 3 56
  • 要事第一是什么 就是把你紧急危险的事放在第一 立刻马上的做这些事。重要但不会有危险不紧急的事。你可以放到后面去做 ...
    挥手告别阅读 179评论 0 1