欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring security原理(1)

程序员文章站 2024-02-20 23:43:04
...

这部分是介绍责任链设计模式,因为spring security是基于过滤器链模式的

这里有一篇文章,很好地介绍了责任链模式
https://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html

下面了解tomcat中过滤器链全过程

1.java servlet规范中,定义了过滤器和过滤器链技术
spring security原理(1)
spring security原理(1)
spring security原理(1)
2.从tomcat的过滤器链开始
tomcat 的过滤器链是ApplicationFilterChain
启动一个springboot web项目,然后从浏览器发送一个请求,在过滤器链开始执行的地方debug看看,如下:
spring security原理(1)
tomcat的过滤器链实现了servlet规范的过滤器链接口
spring security原理(1)
第一个疑问是ApplicationFilterChain将所有的Filter存放在哪里?
答案是保存在ApplicationFilterChain类中的一个ApplicationFilterConfig对象的数组中。
spring security原理(1)
那ApplicationFilterConfig对象又是什么呢?
ApplicationFilterConfig是一个Filter容器
spring security原理(1)
ApplicationFilterConfig实现了过滤器配置接口FilterConfig,以前在web.xml中配置过滤器时如下:
spring security原理(1)
当一个web应用首次启动时ApplicationFilterConfig会自动实例化,它会从该web应用的web.xml文件中读取配置的Filter的信息,然后装进该容器。

刚刚看到在ApplicationFilterChain类中所创建的ApplicationFilterConfig数组长度为零,那它是在什么时候被重新赋值的呢?
是在调用ApplicationFilterChain类的addFilter()方法时,下面源码截图
spring security原理(1)
变量n用来记录当前过滤器链里面拥有的过滤器数目,默认情况下n等于0,ApplicationFilterConfig对象数组的长度也等于0,所以当第一次调用addFilter()方法时,if (n == filters.length)的条件成立,ApplicationFilterConfig数组长度被改变。之后filters[n++] = filterConfig;将变量filterConfig放入ApplicationFilterConfig数组中并将当前过滤器链里面拥有的过滤器数目+1。

那ApplicationFilterChain的addFilter()方法又是在什么地方被调用的呢?
是在ApplicationFilterFactory类的createFilterChain()方法中
查看源码createFilterChain()方法
第一目的是创建ApplicationFilterChain对象以及一些参数设置。
第二目的是从上下文中获取所有Filter信息,之后使用for循环遍历并调用filterChain.addFilter(filterConfig);将filterConfig放入ApplicationFilterChain对象的ApplicationFilterConfig数组中。

那ApplicationFilterFactory类的createFilterChain()方法又是在什么地方被调用的呢?
是在StandardWrapperValue类的invoke()方法中被调用的。看下图:
spring security原理(1)
那正常的流程应该是这样的:

在StandardWrapperValue类的invoke()方法中调用ApplicationFilterChai类的createFilterChain()方法———>在ApplicationFilterChai类的createFilterChain()方法中调用ApplicationFilterChain类的addFilter()方法———>在ApplicationFilterChain类的addFilter()方法中给ApplicationFilterConfig数组赋值。

spring security原理(1)

根据上面的代码可以看出StandardWrapperValue类的invoke()方法在执行完createFilterChain()方法后,会继续执行ApplicationFilterChain类的doFilter()方法,然后在doFilter()方法中会调用internalDoFilter()方法。

以下是internalDoFilter()方法的部分代码

// Call the next filter if there is one
        if (pos < n) {
       //拿到下一个Filter,将指针向下移动一位
            //pos它来标识当前ApplicationFilterChain(当前过滤器链)执行到哪个过滤器
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = null;
            try {
          //获取当前指向的Filter的实例
                filter = filterConfig.getFilter();
                support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
                                          filter, request, response);
                
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                if( Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal = 
                        ((HttpServletRequest) req).getUserPrincipal();

                    Object[] args = new Object[]{req, res, this};
                    SecurityUtil.doAsPrivilege
                        ("doFilter", filter, classType, args, principal);
                    
                } else {
            //调用Filter的doFilter()方法  
                    filter.doFilter(request, response, this);
                }

这里的filter.doFilter(request, response, this);就是调用我们前面创建的TestFilter中的doFilter()方法。而TestFilter中的doFilter()方法会继续调用chain.doFilter(request, response);方法,而这个chain其实就是ApplicationFilterChain,所以调用过程又回到了上面调用dofilter和调用internalDoFilter方法,这样执行直到里面的过滤器全部执行。
上图黄色框部分是自定义的两个过滤器