shiro-web 软件分析
2024-11-16 11:51:18 Author: www.freebuf.com(查看原文) 阅读量:0 收藏

看之前可以先了解:shiro-core 分析

  • shiro-web是shiro-core的wrapper

其特征都是 ”实现一方,调用一方“ 注:调用不一定要显式的调用(代码上的),隐式调用也算,比如子类对于没有重写父类的方法,其字节码的函数引用与父类的一致,所以也可算作子类调用了父类的函数

比如shiro-web实现了Filter接口,从而使得Tomcat可以调用,同时ShiroFilter,又调用了WebSubject,
从抽象的接口的意义上讲,Shiro***Filter调用WebSubject相关验证和授权接口,但这些接口是继承自Subject的,所以会调用Subject接口,从而调用了shiro-core

如图:红色代表shiro-core, 蓝色是shiro-web

这里的ShiroFilter不是具体的某个类,而是代表所有shiro内的Filter

image

从具体实现的意义过程来讲,当然是类调用类,但这是实现,不是"概念",从抽象意义讨论调用过程比较契合概念.

同时由于其是软件级别的wrapper,shiro-core与其wrapper(shiro-web) 不是完全单向的调用关系,某些情况shiro-core会调用wrapper中的实现,比如SessionManager的两种实现

同时shiro-web与Servlet容器也不是单向关系

  • 同时从上图可以看出其符合架构(Architecture)中的分层结构(Layered)

  • session管理冲突:
    Session管理的使用,servlet容器(Tomcat) 已经实现了 的(Tomcat的Session管理(一) - coldridgeValley - 博客园 (cnblogs.com)),所以到底是使用 shrio提供的SessionManager,还是Tomcat已经实现的 是一个需要考虑的选择,shiro当然考虑到了这点

Apache Shiro Web Support | Apache Shiro| session_management

  • subject 不在是“用户”级别 更确切的讲是“请求”级别,因为Servlet Container是以请求为单位进行处理,所以对它来说“主体” 是 请求

结构分析 && 流程分析

shiro-web主要通过继承的方式,让shiro-web容器直接依赖Webxxx自己的类,从而实现shiro-web与shiro-core解耦

eg:

image

image

类似的还有WebSecurityManger,

servlet容器直接依赖shiroFilter,shiroFilter又直接依赖WebSubject,WebSubject又直接依赖WebSecurityManger....它们的逻辑大部分都由shiro-core实现,这种方式使得shiro-web不在代码上直接依赖shiro-core:shiro-web与shiro-core解耦

因此对于这些部分不再赘述,直接看shiro-core即可,只分析shiro-web特有部分;

==由于shiro-web特有部分非常少故直接从实现阶段分析==

Filter

(Architecture,Implement)

image

  • 从OncePerRequestFilter开始有一个分支,其中右边是直接对接servlet容器中的Filter,也就是说对于servlet容器,shiro-web只是一个Filter,其名字为ShiroFilter,(通过web.xml配置)

  • 左边是shiro-web实际执行过滤逻辑的Filter

OncePerRequestFilter

OncePerRequestFilter.doFilter()
image

实际逻辑由doFilterInternal()决定,它由子类实现

ShiroFilter(AbstractShiroFilter)

初始化(读取解析配置文件)

image

doFilter()

AbstractShiroFilter::

image

image

image

getExecutionChain()返回的chain是ProxiedFilterChain,后面讨论

AdviceFilter

A Servlet Filter that enables AOP-style "around" advice for a ServletRequest via preHandle, postHandle, and afterCompletion hooks.

image

preHandle等“advice()"主要由子类实现;

AccessControlFilter

主要分类:最重要的是左边两个分类

image

InvalidRequestFilter:用于封锁恶意请求

UserFilter:
Filter that allows access to resources if the accessor is a known user, which is defined as having a known principal. This means that any user who is authenticated or remembered via a 'remember me' feature will be allowed access from this filter. If the accessor is not a known user, then they will be redirected to the loginUrl

AuthenticationFilter

image

AuthorizationFilter

image

FilterChainManager

A FilterChainManager manages the creation and modificationof Filter chains from an available pool of Filter instances.

image

NamedFilterList extend List
NamedFilterList是装载NameableFilter(及其子类)的列表

image

filters与filterChains是最核心的数据,这些字段在初始化阶段,通过读取解析配置文件获取

eg: shiro.ini

[main]

...

myFilter = com.company.web.some.FilterImplementation
myFilter.property1 = value1

otherFilter = .....
...

[urls]
...

/some/path/** = myFilter,otherFilter

以下是Default Filter及其name
![image](https://image.3001.net/images/20241030/1730281738_6722010adc471f3948b95.png!small)from:[Apache Shiro Web Support\#default\_filters \| Apache Shiro](https://shiro.apache.org/web.html#default_filters)

FilterChainResolver

根据request.url 返回对应的FilterChain

其实现类只有一个:PathMatchingFilterChainResolver

image

实现方式很简单,获取requestUrl, 再遍历所有filterChainNames,并一个一个比对,比对成功则调用FIlterChainManger.proxy(),并返回,也就起到一个匹配filterchainNames的作用

跟进proxy():

//DefaultFilterChainManager::
public FilterChain proxy(FilterChain original, String chainName) {
        NamedFilterList configured = getChain(chainName);//根据名字取出相应的过滤器链
        if (configured == null) {
            String msg = "There is no configured chain under the name/key [" + chainName + "].";
            throw new IllegalArgumentException(msg);
        }
        return configured.proxy(original);  //委托
    }


//SimpleNamedFilterList::
public FilterChain proxy(FilterChain orig) {
        return new ProxiedFilterChain(orig, this);
    }

ProxiedFilterChain

architecture

image

  • filters: shiro实际的过滤器

  • orig: servlet容器中原来的链

  • dofilter()

//ProxiedFilterChain::
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (this.filters == null || this.filters.size() == this.index) {
            //we've reached the end of the wrapped chain, so invoke the original one:
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Invoking original filter chain.");
            }
            this.orig.doFilter(request, response);
        } else {
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Invoking wrapped filter at index [" + this.index + "]");
            }
            this.filters.get(this.index++).doFilter(request, response, this);
        }
    }
}

大致逻辑就是先调用filters的doFilter,当执行完后,就执行orig.doFilter(...) ,这也意味着ShiroFilter结束了

总体流程

根据上述内容得出:(不包括初始化部分)

Main.png


文章来源: https://www.freebuf.com/articles/web/414108.html
如有侵权请联系:admin#unsafe.sh