Spring Boot Shiro在Web應用中的作用詳解
01-Tomcat 中的 Filter 責任鏈
在前面的文章中,我介紹了如何使用 Apache Shiro 進行安全認證。 其實 Shiro 在 Web 應用中出現(xiàn)的頻率更高。 今天我將來分析下,Shiro 是如何應用到 Web 應用中的。
Servlet 規(guī)范中定義了 Filter 和 FilterChain 接口,其中都包含一個 doFilter 方法,不過參數(shù)有區(qū)別:
Filter#doFilter(ServletRequest request, ServletResponse response, FilterChain chain)FilterChain#doFilter(ServletRequest request, ServletResponse response)
Tomcat 中對 FilterChain 的實現(xiàn)是 org.apache.catalina.core.ApplicationFilterChain,它包括:
ApplicationFilterConfig[] filters;數(shù)組,用來保存鏈中的 Filter,ApplicationFilterConfig 是 Filter 的配置類,通過 ApplicationFilterConfig#getFilter() 可獲得對應的 Filter。int pos;表示鏈當前位置。int n;表示 FilterChain 中 Filter 的數(shù)量,即 filters 中元素數(shù)量。Servlet servlet;表示應用的 Servlet 實現(xiàn)。
ApplicationFilterChain#doFilter 的實現(xiàn)邏輯:
- 如果
pos < n,即尚未執(zhí)行到鏈表末端,則調(diào)用filters[pos++].getFilter().doFilter(req, res, chain),執(zhí)行當前 Filter 的 doFilter 方法。 - 如果
pos >= n,說明鏈表中所有的 Filter 都執(zhí)行完畢,則調(diào)用servlet.service(request, response);,執(zhí)行業(yè)務層邏輯。
綜上,ApplicationFilterChain 會檢查是否有 Filter 需要執(zhí)行,如果有,則調(diào)用 Filter;否則,則將請求交給 Servlet 處理。 Filter 在其 doFilter 方法中,能夠拿到當前 Filter 所述的 FilterChain 對象。 在執(zhí)行完 Filter 后,根據(jù)自身邏輯判斷是否需要繼續(xù)將請求傳遞給 chain 上的后續(xù) Filter 處理,若需要,則調(diào)用 chain 的 doFilter 方法。
02-Shiro 中的 filter 鏈結(jié)構(gòu)
Shiro 中對 FilterChain 的實現(xiàn)是 org.apache.shiro.web.servlet.ProxiedFilterChain,它包括:
FilterChain orig;它是 Tomcat 中的 FilterChain 實例。List<Filter> filters;是 Shiro 中要執(zhí)行的安全相關的 Filter(它們也都是實現(xiàn)了 Servlet Filter 的類)。int index;與 ApplicationFilterChain 中的 pos 異曲同工之妙。
ProxiedFilterChain#doFilter 的實現(xiàn)邏輯:
- 如果
filters == null || index = filters.size()說明 Shiro 中安全相關的鏈已執(zhí)行完畢,則調(diào)用orig.doFilter(req, res) - 否則,說明鏈中當其 Filter 需要執(zhí)行,則調(diào)用
filters.get(index++).doFilter(request, response, this);
03-shiro-filters 如何與 servlet 中的 filter 關聯(lián)起來
org.apache.shiro.web.servlet.OncePerRequestFilter 實現(xiàn)了 Servlet 中的 Filter 接口,org.apache.shiro.web.servlet.AbstractShiroFilter 是 OncePerRequestFilter 的基本實現(xiàn)。 因此,AbstractShiroFilter 的派生類都能作為 Filter 添加到 Servlet 的責任鏈中,即 ApplicationFilterChain 的 filters 中。
Shiro 將 AbstractShiroFilter 的一個實現(xiàn) org.apache.shiro.spring.web.ShiroFilterFactoryBean.SpringShiroFilter 添加到 filters 中,并命名為 "shiroFilter"。 該類的繼承關系如下:

注:org.apache.shiro.web.servlet.OncePerRequestFilter 與 Spring 中的 OncePerRequestFilter 同名,但實現(xiàn)不同。
將 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 中實現(xiàn)了 Filter#doFilter 方法,并在該方法中將過濾器的處理邏輯交由其定義的模板方法 doFilterInternal 來實現(xiàn)。 AbstractShiroFilter 提供了對 doFilterInternal 的基本實現(xiàn):
將 HttpServletRequest 包裝成 ShiroHttpServletRequest
將 HttpServletResponse 包裝成 ShiroHttpServletResponse
- 創(chuàng)建 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 類似。
當請求經(jīng)過 ApplicationFilterChain 處理,進入到 shiroFilter 時,它的 doFilter 方法(在 OncePerRequestFilter 中)將請求交給 doFilterInternal 方法(在 AbstractShiroFilter 中)處理。 然后會執(zhí)行與請求路徑相關聯(lián)的 shiro-filter 組成的 chain 對請求、響應進行處理。 下圖是 shiro-chain 與 application chain 之間的關系,可以參考下幫助加深理解。

04-總結(jié)
今天介紹了 Tomcat 中 Filter 責任鏈的作用原理以及 Shiro 中實現(xiàn)的安全相關的 Filter 責任鏈。 并且,還分析了 Shiro 是如何作為一個 Filter 應用到 Web 應用的。 綜上,我們了解了一個請求是如何經(jīng)過層層 Filter 到達 Servlet 中的,也了解了 Shiro 是如何在這個流程中發(fā)揮安全認證作用的。 希望以上的內(nèi)容能對你有所幫助。
以上就是Spring Boot Shiro在Web應用中的作用詳解的詳細內(nèi)容,更多關于Spring Boot Shiro Web的資料請關注腳本之家其它相關文章!
相關文章
Spring boot如何基于攔截器實現(xiàn)訪問權(quán)限限制
這篇文章主要介紹了Spring boot如何基于攔截器實現(xiàn)訪問權(quán)限限制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-10-10
spring+maven實現(xiàn)發(fā)送郵件功能
這篇文章主要為大家詳細介紹了spring+maven實現(xiàn)發(fā)送郵件功能,利用spring提供的郵件工具來發(fā)送郵件,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-07-07
Spring中的@EnableConfigurationProperties使用方式以及作用詳解
這篇文章主要介紹了Spring中的@EnableConfigurationProperties使用方式以及作用詳解,使用了?@ConfigurationProperties?注解的配置類生效,將該類注入到?IOC?容器中,交由?IOC?容器進行管理,此時則不用再配置類上加上@Component,需要的朋友可以參考下2024-01-01
SpringBoot+vue實現(xiàn)登錄圖片驗證碼功能
這篇文章主要給大家介紹一下如何SpringBoot+vue實現(xiàn)登錄圖片驗證碼功能,文中有詳細的代碼示例,具有一定的參考價值,需要的朋友可以參考下2023-07-07
手把手帶你分析SpringBoot自動裝配完成了Ribbon哪些核心操作
這篇文章主要介紹了詳解Spring Boot自動裝配Ribbon哪些核心操作的哪些操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-08-08
Java 精煉解讀數(shù)據(jù)結(jié)構(gòu)邏輯控制
在程序開發(fā)的過程之中一共會存在有三種程序邏輯:順序結(jié)構(gòu)、分支結(jié)構(gòu)、循環(huán)結(jié)構(gòu),對于之前所編寫的代碼大部分都是順序結(jié)構(gòu)的定義,即:所有的程序?qū)凑斩x的代碼順序依次執(zhí)行2022-03-03

