Spring Boot Shiro在Web應(yīng)用中的作用詳解
01-Tomcat 中的 Filter 責(zé)任鏈
在前面的文章中,我介紹了如何使用 Apache Shiro 進(jìn)行安全認(rèn)證。 其實(shí) Shiro 在 Web 應(yīng)用中出現(xiàn)的頻率更高。 今天我將來(lái)分析下,Shiro 是如何應(yīng)用到 Web 應(yīng)用中的。
Servlet 規(guī)范中定義了 Filter 和 FilterChain 接口,其中都包含一個(gè) doFilter 方法,不過(guò)參數(shù)有區(qū)別:
Filter#doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
FilterChain#doFilter(ServletRequest request, ServletResponse response)
Tomcat 中對(duì) FilterChain 的實(shí)現(xiàn)是 org.apache.catalina.core.ApplicationFilterChain
,它包括:
ApplicationFilterConfig[] filters;
數(shù)組,用來(lái)保存鏈中的 Filter,ApplicationFilterConfig 是 Filter 的配置類,通過(guò) ApplicationFilterConfig#getFilter() 可獲得對(duì)應(yīng)的 Filter。int pos;
表示鏈當(dāng)前位置。int n;
表示 FilterChain 中 Filter 的數(shù)量,即 filters 中元素?cái)?shù)量。Servlet servlet;
表示應(yīng)用的 Servlet 實(shí)現(xiàn)。
ApplicationFilterChain#doFilter 的實(shí)現(xiàn)邏輯:
- 如果
pos < n
,即尚未執(zhí)行到鏈表末端,則調(diào)用filters[pos++].getFilter().doFilter(req, res, chain)
,執(zhí)行當(dāng)前 Filter 的 doFilter 方法。 - 如果
pos >= n
,說(shuō)明鏈表中所有的 Filter 都執(zhí)行完畢,則調(diào)用servlet.service(request, response);
,執(zhí)行業(yè)務(wù)層邏輯。
綜上,ApplicationFilterChain 會(huì)檢查是否有 Filter 需要執(zhí)行,如果有,則調(diào)用 Filter;否則,則將請(qǐng)求交給 Servlet 處理。 Filter 在其 doFilter 方法中,能夠拿到當(dāng)前 Filter 所述的 FilterChain 對(duì)象。 在執(zhí)行完 Filter 后,根據(jù)自身邏輯判斷是否需要繼續(xù)將請(qǐng)求傳遞給 chain 上的后續(xù) Filter 處理,若需要,則調(diào)用 chain 的 doFilter 方法。
02-Shiro 中的 filter 鏈結(jié)構(gòu)
Shiro 中對(duì) FilterChain 的實(shí)現(xiàn)是 org.apache.shiro.web.servlet.ProxiedFilterChain
,它包括:
FilterChain orig;
它是 Tomcat 中的 FilterChain 實(shí)例。List<Filter> filters;
是 Shiro 中要執(zhí)行的安全相關(guān)的 Filter(它們也都是實(shí)現(xiàn)了 Servlet Filter 的類)。int index;
與 ApplicationFilterChain 中的 pos 異曲同工之妙。
ProxiedFilterChain#doFilter 的實(shí)現(xiàn)邏輯:
- 如果
filters == null || index = filters.size()
說(shuō)明 Shiro 中安全相關(guān)的鏈已執(zhí)行完畢,則調(diào)用orig.doFilter(req, res)
- 否則,說(shuō)明鏈中當(dāng)其 Filter 需要執(zhí)行,則調(diào)用
filters.get(index++).doFilter(request, response, this);
03-shiro-filters 如何與 servlet 中的 filter 關(guān)聯(lián)起來(lái)
org.apache.shiro.web.servlet.OncePerRequestFilter 實(shí)現(xiàn)了 Servlet 中的 Filter 接口,org.apache.shiro.web.servlet.AbstractShiroFilter 是 OncePerRequestFilter 的基本實(shí)現(xiàn)。 因此,AbstractShiroFilter 的派生類都能作為 Filter 添加到 Servlet 的責(zé)任鏈中,即 ApplicationFilterChain 的 filters 中。
Shiro 將 AbstractShiroFilter 的一個(gè)實(shí)現(xiàn) org.apache.shiro.spring.web.ShiroFilterFactoryBean.SpringShiroFilter
添加到 filters 中,并命名為 "shiroFilter"。 該類的繼承關(guān)系如下:
注:org.apache.shiro.web.servlet.OncePerRequestFilter 與 Spring 中的 OncePerRequestFilter 同名,但實(shí)現(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 實(shí)例 filterRegistrationBean.setName(FILTER_NAME); // "shiroFilter" filterRegistrationBean.setOrder(1); return filterRegistrationBean; } 復(fù)制代碼
使用 DEBUG 方式 Shiro Web 應(yīng)用,也可以佐證上述觀點(diǎn):
Shiro 在 OncePerRequestFilter 中實(shí)現(xiàn)了 Filter#doFilter 方法,并在該方法中將過(guò)濾器的處理邏輯交由其定義的模板方法 doFilterInternal 來(lái)實(shí)現(xiàn)。 AbstractShiroFilter 提供了對(duì) doFilterInternal 的基本實(shí)現(xiàn):
將 HttpServletRequest 包裝成 ShiroHttpServletRequest
將 HttpServletResponse 包裝成 ShiroHttpServletResponse
- 創(chuàng)建 WebSubject
executeChain(request, response, origChain);
,其中 origChain 是 Tomcat 處理請(qǐng)求響應(yīng)的 ApplicationFilterChain,即 shiroFilter 所在的 chain。
chain = PathMatchingFilterChainResolver#getChain(request, response, origChain);
chain 是前面提到的 ProxiedFilterChain 實(shí)例。
chain.doFilter(request, response);
,相當(dāng)于將請(qǐng)求交給 shiro-filter 組成的 chain 處理,大體流程與 ApplicationFilterChain 類似。
當(dāng)請(qǐng)求經(jīng)過(guò) ApplicationFilterChain 處理,進(jìn)入到 shiroFilter 時(shí),它的 doFilter 方法(在 OncePerRequestFilter 中)將請(qǐng)求交給 doFilterInternal 方法(在 AbstractShiroFilter 中)處理。 然后會(huì)執(zhí)行與請(qǐng)求路徑相關(guān)聯(lián)的 shiro-filter 組成的 chain 對(duì)請(qǐng)求、響應(yīng)進(jìn)行處理。 下圖是 shiro-chain 與 application chain 之間的關(guān)系,可以參考下幫助加深理解。
04-總結(jié)
今天介紹了 Tomcat 中 Filter 責(zé)任鏈的作用原理以及 Shiro 中實(shí)現(xiàn)的安全相關(guān)的 Filter 責(zé)任鏈。 并且,還分析了 Shiro 是如何作為一個(gè) Filter 應(yīng)用到 Web 應(yīng)用的。 綜上,我們了解了一個(gè)請(qǐng)求是如何經(jīng)過(guò)層層 Filter 到達(dá) Servlet 中的,也了解了 Shiro 是如何在這個(gè)流程中發(fā)揮安全認(rèn)證作用的。 希望以上的內(nèi)容能對(duì)你有所幫助。
以上就是Spring Boot Shiro在Web應(yīng)用中的作用詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot Shiro Web的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot2 參數(shù)管理實(shí)踐之入?yún)⒊鰠⑴c校驗(yàn)的方式
這篇文章主要介紹了SpringBoot2 參數(shù)管理實(shí)踐,入?yún)⒊鰠⑴c校驗(yàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-06-06Spring Boot中@value的常見(jiàn)用法及案例
@Value注解是Spring框架中強(qiáng)大且常用的注解之一,本文主要介紹了SpringBoot中@value的常見(jiàn)用法及案例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09SpringBoot中的@Conditional?注解的使用
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件的才給容器注冊(cè)Bean,本文主要介紹了SpringBoot中的@Conditional?注解的使用2024-01-01關(guān)于Socket的解析以及雙方即時(shí)通訊的java實(shí)現(xiàn)方法
本篇文章主要介紹了關(guān)于Socket的解析以及雙方通訊的java實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03Dubbo擴(kuò)展點(diǎn)SPI實(shí)踐示例解析
這篇文章主要為大家介紹了Dubbo擴(kuò)展點(diǎn)SPI實(shí)踐示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Java中實(shí)現(xiàn)List分隔成子List詳解
大家好,本篇文章主要講的是Java中實(shí)現(xiàn)List分隔成子List詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01java動(dòng)態(tài)方法調(diào)度實(shí)例分析
這篇文章主要介紹了java動(dòng)態(tài)方法調(diào)度,結(jié)合實(shí)例形式對(duì)比分析了java的動(dòng)態(tài)方法調(diào)度原理、使用方法與注意事項(xiàng),需要的朋友可以參考下2016-06-06