Spring Boot Shiro在Web应用中的作用详解
01-Tomcat 中的 Filter 责任链
在前面的文章中,我介绍了如何使用 Apache Shiro 进行安全认证。 其实 Shiro 在 Web 应用中出现的频率更高。 今天我将来分析下,Shiro 是如何应用到 Web 应用中的。
Servlet 规范中定义了 Filter 和 FilterChain 接口,其中都包含一个 doFilter 方法,不过参数有区别:
Filter#doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
FilterChain#doFilter(ServletRequest request, ServletResponse response)
Tomcat 中对 FilterChain 的实现是 org.apache.catalina.core.ApplicationFilterChain
,它包括:
ApplicationFilterConfig[] filters;
数组,用来保存链中的 Filter,ApplicationFilterConfig 是 Filter 的配置类,通过 ApplicationFilterConfig#getFilter() 可获得对应的 Filter。int pos;
表示链当前位置。int n;
表示 FilterChain 中 Filter 的数量,即 filters 中元素数量。Servlet servlet;
表示应用的 Servlet 实现。
ApplicationFilterChain#doFilter 的实现逻辑:
- 如果
pos < n
,即尚未执行到链表末端,则调用filters[pos++].getFilter().doFilter(req, res, chain)
,执行当前 Filter 的 doFilter 方法。 - 如果
pos >= n
,说明链表中所有的 Filter 都执行完毕,则调用servlet.service(request, response);
,执行业务层逻辑。
综上,ApplicationFilterChain 会检查是否有 Filter 需要执行,如果有,则调用 Filter;否则,则将请求交给 Servlet 处理。 Filter 在其 doFilter 方法中,能够拿到当前 Filter 所述的 FilterChain 对象。 在执行完 Filter 后,根据自身逻辑判断是否需要继续将请求传递给 chain 上的后续 Filter 处理,若需要,则调用 chain 的 doFilter 方法。
02-Shiro 中的 filter 链结构
Shiro 中对 FilterChain 的实现是 org.apache.shiro.web.servlet.ProxiedFilterChain
,它包括:
FilterChain orig;
它是 Tomcat 中的 FilterChain 实例。List<Filter> filters;
是 Shiro 中要执行的安全相关的 Filter(它们也都是实现了 Servlet Filter 的类)。int index;
与 ApplicationFilterChain 中的 pos 异曲同工之妙。
ProxiedFilterChain#doFilter 的实现逻辑:
- 如果
filters == null || index = filters.size()
说明 Shiro 中安全相关的链已执行完毕,则调用orig.doFilter(req, res)
- 否则,说明链中当其 Filter 需要执行,则调用
filters.get(index++).doFilter(request, response, this);
03-shiro-filters 如何与 servlet 中的 filter 关联起来
org.apache.shiro.web.servlet.OncePerRequestFilter 实现了 Servlet 中的 Filter 接口,org.apache.shiro.web.servlet.AbstractShiroFilter 是 OncePerRequestFilter 的基本实现。 因此,AbstractShiroFilter 的派生类都能作为 Filter 添加到 Servlet 的责任链中,即 ApplicationFilterChain 的 filters 中。
Shiro 将 AbstractShiroFilter 的一个实现 org.apache.shiro.spring.web.ShiroFilterFactoryBean.SpringShiroFilter
添加到 filters 中,并命名为 "shiroFilter"。 该类的继承关系如下:
注:org.apache.shiro.web.servlet.OncePerRequestFilter 与 Spring 中的 OncePerRequestFilter 同名,但实现不同。
将 shiroFilter 添加到 filters 中的逻辑在 org.apache.shiro.spring.config.web.autoconfigure.ShiroWebFilterConfiguration
中:
@Bean(name = REGISTRATION_BEAN_NAME) @ConditionalOnMissingBean(name = REGISTRATION_BEAN_NAME) protected FilterRegistrationBean<AbstractShiroFilter> filterShiroFilterRegistrationBean() throws Exception { FilterRegistrationBean<AbstractShiroFilter> filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR); filterRegistrationBean.setFilter((AbstractShiroFilter) shiroFilterFactoryBean().getObject()); // SpringShiroFilter 实例 filterRegistrationBean.setName(FILTER_NAME); // "shiroFilter" filterRegistrationBean.setOrder(1); return filterRegistrationBean; } 复制代码
使用 DEBUG 方式 Shiro Web 应用,也可以佐证上述观点:
Shiro 在 OncePerRequestFilter 中实现了 Filter#doFilter 方法,并在该方法中将过滤器的处理逻辑交由其定义的模板方法 doFilterInternal 来实现。 AbstractShiroFilter 提供了对 doFilterInternal 的基本实现:
将 HttpServletRequest 包装成 ShiroHttpServletRequest
将 HttpServletResponse 包装成 ShiroHttpServletResponse
- 创建 WebSubject
executeChain(request, response, origChain);
,其中 origChain 是 Tomcat 处理请求响应的 ApplicationFilterChain,即 shiroFilter 所在的 chain。
chain = PathMatchingFilterChainResolver#getChain(request, response, origChain);
chain 是前面提到的 ProxiedFilterChain 实例。
chain.doFilter(request, response);
,相当于将请求交给 shiro-filter 组成的 chain 处理,大体流程与 ApplicationFilterChain 类似。
当请求经过 ApplicationFilterChain 处理,进入到 shiroFilter 时,它的 doFilter 方法(在 OncePerRequestFilter 中)将请求交给 doFilterInternal 方法(在 AbstractShiroFilter 中)处理。 然后会执行与请求路径相关联的 shiro-filter 组成的 chain 对请求、响应进行处理。 下图是 shiro-chain 与 application chain 之间的关系,可以参考下帮助加深理解。
04-总结
今天介绍了 Tomcat 中 Filter 责任链的作用原理以及 Shiro 中实现的安全相关的 Filter 责任链。 并且,还分析了 Shiro 是如何作为一个 Filter 应用到 Web 应用的。 综上,我们了解了一个请求是如何经过层层 Filter 到达 Servlet 中的,也了解了 Shiro 是如何在这个流程中发挥安全认证作用的。 希望以上的内容能对你有所帮助。
以上就是Spring Boot Shiro在Web应用中的作用详解的详细内容,更多关于Spring Boot Shiro Web的资料请关注脚本之家其它相关文章!
相关文章
maven assembly打包生成Java应用启动脚本bat和sh的方法
springboot应用通过maven插件appassembler-maven-plugi生成启动脚本bat和sh,这篇文章主要介绍了maven assembly打包生成Java应用启动脚本bat和sh,需要的朋友可以参考下2022-11-11
最新评论