shiro-web 软件分析
字数 2669 2025-08-20 18:17:58

Apache Shiro Web 模块深入分析与教学文档

1. Shiro-Web 概述

Shiro-Web 是 Shiro-Core 的包装器(wrapper),主要提供与 Servlet 容器的集成能力。其核心特征是"实现一方,调用一方"的设计模式:

  • 实现 Filter 接口使 Tomcat 可以调用
  • ShiroFilter 调用 WebSubject
  • WebSubject 调用 Subject 接口(继承自 shiro-core)

关键特性

  1. 双向调用关系

    • 主要调用方向:shiro-web → shiro-core
    • 特殊情况:shiro-core 也会回调 wrapper 中的实现(如 SessionManager 的两种实现)
  2. Session 管理冲突处理

    • Servlet 容器(如 Tomcat)已有 Session 管理实现
    • Shiro 提供了自己的 SessionManager
    • 开发者需要选择使用哪种 Session 管理方式

2. 架构设计与解耦机制

Shiro-Web 通过继承方式实现与核心模块的解耦:

Servlet容器 → ShiroFilter → WebSubject → WebSecurityManager

这种设计使得:

  • shiro-web 不直接依赖 shiro-core
  • 大部分逻辑由 shiro-core 实现
  • shiro-web 只需关注特定于 Web 的部分

3. Filter 体系结构

3.1 类图结构

OncePerRequestFilter
├── 直接对接 Servlet 容器的 Filter 分支
└── 实际执行过滤逻辑的 Filter 分支
    └── AbstractShiroFilter (ShiroFilter)
        └── AdviceFilter
            └── AccessControlFilter
                ├── InvalidRequestFilter (封锁恶意请求)
                └── UserFilter (允许已知用户访问)

3.2 核心 Filter 详解

OncePerRequestFilter:

  • doFilter() 方法实际逻辑由 doFilterInternal() 决定(子类实现)
  • 确保每个请求只被过滤一次

AbstractShiroFilter:

  • 初始化:读取解析配置文件
  • 核心算法:
    1. 获取执行链
    2. 执行过滤操作

AdviceFilter:

  • 提供 AOP 风格的"环绕"通知:
    • preHandle: 请求处理前
    • postHandle: 请求处理后
    • afterCompletion: 请求完成后

AccessControlFilter:

  • 访问控制基类
  • 主要子类:
    • InvalidRequestFilter: 封锁恶意请求
    • UserFilter: 仅允许已知用户(已认证或记住我)访问

4. Filter 链管理

4.1 FilterChainManager

管理从可用 Filter 实例池中创建和修改 Filter 链。

关键组件:

  • NamedFilterList: 装载 NameableFilter 及其子类的列表
  • NameableFilter: 配置文件中配置的过滤器

4.2 配置示例

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

[urls]
/login = authc
/admin = authc, roles[admin]
/user = authc, roles[user]
/** = anon

URL 配置格式:

/some/path/** = myFilter,otherFilter

表示该路径需要经过 myFilter 和 otherFilter 两个过滤器

4.3 默认过滤器

Shiro 提供了一组默认过滤器(如 authc, anon, roles 等),可直接在配置中使用。

5. FilterChainResolver

根据请求 URL 返回对应的 FilterChain。

唯一实现类:PathMatchingFilterChainResolver

工作流程:

  1. 获取 requestUrl
  2. 遍历所有 filterChainNames (pathPattern)
  3. 逐个比对,匹配成功则调用 FilterChainManager.proxy(originalChain, pathPattern)

proxy() 方法详解:

// DefaultFilterChainManager
public FilterChain proxy(FilterChain original, String chainName) {
    NamedFilterList configured = getChain(chainName); // 获取配置的过滤器链
    if (configured == null) {
        throw new IllegalArgumentException("No configured chain under name [" + chainName + "]");
    }
    return configured.proxy(original); // 代理
}

// SimpleNamedFilterList
public FilterChain proxy(FilterChain orig) {
    return new ProxiedFilterChain(orig, this); // 创建代理链
}

6. ProxiedFilterChain 架构

public class ProxiedFilterChain implements FilterChain {
    private FilterChain orig; // Servlet 容器原始链
    private List<Filter> filters; // Shiro 实际过滤器
    private int index = 0; // 当前过滤器索引
    
    public void doFilter(ServletRequest request, ServletResponse response) {
        if (this.filters == null || this.filters.size() == this.index) {
            // 执行完 Shiro 过滤器后,调用原始链
            this.orig.doFilter(request, response);
        } else {
            // 执行当前 Shiro 过滤器
            this.filters.get(this.index++).doFilter(request, response, this);
        }
    }
}

7. 总体流程

  1. 请求到达 ShiroFilter (AbstractShiroFilter)
  2. 通过 FilterChainResolver 获取匹配的 FilterChain
  3. 创建 ProxiedFilterChain (包装原始 FilterChain 和 Shiro 过滤器)
  4. 执行 ProxiedFilterChain 的 doFilter 方法:
    • 先执行所有 Shiro 过滤器
    • 最后执行原始 Servlet 容器过滤器链
  5. 过滤完成后,请求继续 Servlet 容器的正常处理流程

8. 关键设计模式

  1. Wrapper 模式:

    • shiro-web 作为 shiro-core 的包装器
    • 提供 Web 特定功能,同时重用核心逻辑
  2. 责任链模式:

    • FilterChain 管理多个过滤器的执行顺序
    • ProxiedFilterChain 实现过滤器链的代理
  3. 模板方法模式:

    • OncePerRequestFilter 定义算法骨架
    • 具体过滤逻辑由子类实现 (doFilterInternal)
  4. 策略模式:

    • FilterChainResolver 提供不同的匹配策略
    • 目前只有 PathMatchingFilterChainResolver 实现

9. 最佳实践

  1. Session 管理选择:

    • 评估是否需要 Shiro 的 SessionManager
    • 考虑与容器 Session 的兼容性
  2. 过滤器配置:

    • 合理使用默认过滤器
    • 自定义过滤器时继承适当的基类
  3. URL 匹配:

    • 精确路径优先于通配符
    • 注意过滤器顺序的影响
  4. 性能考虑:

    • 避免过于复杂的过滤器链
    • 利用 OncePerRequestFilter 避免重复过滤

10. 扩展点

  1. 自定义 Filter:

    • 继承 AccessControlFilter 或 AdviceFilter
    • 实现特定的访问控制逻辑
  2. 自定义 FilterChainResolver:

    • 实现不同的 URL 匹配策略
    • 如基于正则表达式或其他条件
  3. SessionManager 集成:

    • 实现自定义 SessionManager
    • 集成第三方 Session 存储

11. 常见问题解决方案

  1. 过滤器不生效:

    • 检查 web.xml 配置
    • 验证 URL 模式匹配
    • 确认过滤器顺序
  2. Session 冲突:

    • 明确选择 Session 管理方式
    • 必要时实现自定义 SessionManager
  3. 性能问题:

    • 减少不必要的过滤器
    • 优化 URL 匹配模式
  4. 安全漏洞:

    • 确保使用 InvalidRequestFilter
    • 定期更新 Shiro 版本

12. 总结

Shiro-Web 通过精心的设计实现了:

  • 与 Servlet 容器的无缝集成
  • 与核心模块的清晰解耦
  • 灵活的过滤器链管理
  • 可扩展的安全控制机制

理解其内部机制有助于:

  • 更有效地使用 Shiro 进行 Web 安全防护
  • 更快速地定位和解决问题
  • 更灵活地进行定制开发
Apache Shiro Web 模块深入分析与教学文档 1. Shiro-Web 概述 Shiro-Web 是 Shiro-Core 的包装器(wrapper),主要提供与 Servlet 容器的集成能力。其核心特征是"实现一方,调用一方"的设计模式: 实现 Filter 接口使 Tomcat 可以调用 ShiroFilter 调用 WebSubject WebSubject 调用 Subject 接口(继承自 shiro-core) 关键特性 双向调用关系 : 主要调用方向:shiro-web → shiro-core 特殊情况:shiro-core 也会回调 wrapper 中的实现(如 SessionManager 的两种实现) Session 管理冲突处理 : Servlet 容器(如 Tomcat)已有 Session 管理实现 Shiro 提供了自己的 SessionManager 开发者需要选择使用哪种 Session 管理方式 2. 架构设计与解耦机制 Shiro-Web 通过继承方式实现与核心模块的解耦: 这种设计使得: shiro-web 不直接依赖 shiro-core 大部分逻辑由 shiro-core 实现 shiro-web 只需关注特定于 Web 的部分 3. Filter 体系结构 3.1 类图结构 3.2 核心 Filter 详解 OncePerRequestFilter : doFilter() 方法实际逻辑由 doFilterInternal() 决定(子类实现) 确保每个请求只被过滤一次 AbstractShiroFilter : 初始化:读取解析配置文件 核心算法: 获取执行链 执行过滤操作 AdviceFilter : 提供 AOP 风格的"环绕"通知: preHandle : 请求处理前 postHandle : 请求处理后 afterCompletion : 请求完成后 AccessControlFilter : 访问控制基类 主要子类: InvalidRequestFilter : 封锁恶意请求 UserFilter : 仅允许已知用户(已认证或记住我)访问 4. Filter 链管理 4.1 FilterChainManager 管理从可用 Filter 实例池中创建和修改 Filter 链。 关键组件: NamedFilterList : 装载 NameableFilter 及其子类的列表 NameableFilter : 配置文件中配置的过滤器 4.2 配置示例 URL 配置格式: 表示该路径需要经过 myFilter 和 otherFilter 两个过滤器 4.3 默认过滤器 Shiro 提供了一组默认过滤器(如 authc, anon, roles 等),可直接在配置中使用。 5. FilterChainResolver 根据请求 URL 返回对应的 FilterChain。 唯一实现类: PathMatchingFilterChainResolver 工作流程: 获取 requestUrl 遍历所有 filterChainNames (pathPattern) 逐个比对,匹配成功则调用 FilterChainManager.proxy(originalChain, pathPattern) proxy() 方法详解: 6. ProxiedFilterChain 架构 7. 总体流程 请求到达 ShiroFilter (AbstractShiroFilter) 通过 FilterChainResolver 获取匹配的 FilterChain 创建 ProxiedFilterChain (包装原始 FilterChain 和 Shiro 过滤器) 执行 ProxiedFilterChain 的 doFilter 方法: 先执行所有 Shiro 过滤器 最后执行原始 Servlet 容器过滤器链 过滤完成后,请求继续 Servlet 容器的正常处理流程 8. 关键设计模式 Wrapper 模式 : shiro-web 作为 shiro-core 的包装器 提供 Web 特定功能,同时重用核心逻辑 责任链模式 : FilterChain 管理多个过滤器的执行顺序 ProxiedFilterChain 实现过滤器链的代理 模板方法模式 : OncePerRequestFilter 定义算法骨架 具体过滤逻辑由子类实现 (doFilterInternal) 策略模式 : FilterChainResolver 提供不同的匹配策略 目前只有 PathMatchingFilterChainResolver 实现 9. 最佳实践 Session 管理选择 : 评估是否需要 Shiro 的 SessionManager 考虑与容器 Session 的兼容性 过滤器配置 : 合理使用默认过滤器 自定义过滤器时继承适当的基类 URL 匹配 : 精确路径优先于通配符 注意过滤器顺序的影响 性能考虑 : 避免过于复杂的过滤器链 利用 OncePerRequestFilter 避免重复过滤 10. 扩展点 自定义 Filter : 继承 AccessControlFilter 或 AdviceFilter 实现特定的访问控制逻辑 自定义 FilterChainResolver : 实现不同的 URL 匹配策略 如基于正则表达式或其他条件 SessionManager 集成 : 实现自定义 SessionManager 集成第三方 Session 存储 11. 常见问题解决方案 过滤器不生效 : 检查 web.xml 配置 验证 URL 模式匹配 确认过滤器顺序 Session 冲突 : 明确选择 Session 管理方式 必要时实现自定义 SessionManager 性能问题 : 减少不必要的过滤器 优化 URL 匹配模式 安全漏洞 : 确保使用 InvalidRequestFilter 定期更新 Shiro 版本 12. 总结 Shiro-Web 通过精心的设计实现了: 与 Servlet 容器的无缝集成 与核心模块的清晰解耦 灵活的过滤器链管理 可扩展的安全控制机制 理解其内部机制有助于: 更有效地使用 Shiro 进行 Web 安全防护 更快速地定位和解决问题 更灵活地进行定制开发