freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

shiro-web 软件分析
2025-01-06 15:41:43
所属地 广东省

shiro-web

看之前可以先了解: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容器也不是单向关系

Apache Shiro Web Support | Apache Shiro| session_management

结构分析 && 流程分析

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

类图
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
关于获取执行链:先获取一个FilterChainResolver,然后调用getChain(request,response,oriChain)
image

getExecutionChain()返回的chain是ProxiedFilterChain,以及oriChain是servlet容器中实际的过滤链后面讨论

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(及其子类)的列表,(NameableFilter在上面Filter部分的图中),NameableFilter是我们在配置文件中配置的过滤器:

[main]
shiro.loginUrl = /login
shiro.successUrl = /loginSuccess


filtername = className
[users]
# format: username = password, role1, role2, ..., roleN

admin=123456,admin
user=123456,user



[roles]
# format: roleName = permission1, permission2, ..., permissionN
admin=*
user=user:query

# value部分就是NameableFilter
[urls]
/login = authc
/admin = authc, roles[admin]
/user = authc , roles[user]
/** = anon

key是url同时也是filterChain的名字,value部分是filtername,可以配置多个filtername(必须在main部分声明filtername = className,除非使用的是Default Filter),在[urls]部分中
/some/path/** = myFilter,otherFilter
表示的意思是,当前这个路径(/some/path/**)需要经过 myFilter,otherFilter两个filter

以下是Default Filter
imagefrom:Apache Shiro Web Support#default_filters | Apache Shiro

FilterChainResolver

根据request.url 返回对应的FilterChain

其实现类只有一个:PathMatchingFilterChainResolver

image

实现方式很简单,(1)获取requestUrl, (2)再遍历所有filterChainNames(pathPattern),并一个一个比对,比对成功则调用FIlterChainManger.proxy(originalChian,pathPattern),并返回,

跟进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) {
//调用构造函数,传入servlet容器中的过滤器链(orig)和shiro自身的链(NamedFilterList)
        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(...) ,从而执行servlet容器中下一个过滤器,这也意味着ShiroFilter结束了
Ma.png

总体流程

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

# Java代码审计 # 软件分析
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录