apahce shiro:1.6.0,依賴shiro-web部分
一、shiro與web集成
1、Shiro1.1 及以前版本配置方式
使用org.apache.shiro.web.servlet.IniShiroFilter作為Shiro安全控制的入口點。
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="false"> <!--- shiro 1.1 --> <filter> <filter-name>iniShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> <init-param> <param-name>configPath</param-name> <param-value>classpath:shiro.ini</param-value> <!--默認先從/WEB-INF/shiro.ini,如果沒有找classpath:shiro.ini--> </init-param> <init-param> <param-name>config</param-name> <param-value> [main] authc.loginUrl=/login [users] zhang=123,admin [roles] admin=user:*,menu:* [urls] /login=anon /static/**=anon /authenticated=authc /role=authc,roles[admin] /permission=authc,perms["user:create"] </param-value> </init-param> </filter> <filter-mapping> <filter-name>iniShiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <error-page> <error-code>401</error-code> <location>/WEB-INF/jsp/unauthorized.jsp</location> </error-page> </web-app>
2、Shiro 1.2 及以后版本的配置方式
使用org.apache.shiro.web.env.EnvironmentLoaderListener來創建相應的WebEnvironment,並自動綁定到ServletContext,默認使用org.apache.shiro.web.env.IniWebEnvironment實現。
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="false"> <!--- shiro 1.2 --> <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> <context-param> <param-name>shiroEnvironmentClass</param-name> <param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value><!-- 默認先從/WEB-INF/shiro.ini,如果沒有找classpath:shiro.ini --> </context-param> <context-param> <param-name>shiroConfigLocations</param-name> <param-value>classpath:shiro.ini</param-value> </context-param> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
3、與Spring集成
使用org.springframework.web.filter.DelegatingFilterProxy作為入口,DelegatingFilterProxy自動到spring容器查找名字為 shiroFilter的bean並把所有 Filter 的操作委托給它。然后將ShiroFilter配置到spring容器即可
目前基本上都是用於spring集成的方式。
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="false"> <!-- Spring配置文件開始 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-beans.xml, classpath:spring-shiro-web.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Spring配置文件結束 --> <!-- shiro 安全過濾器 --> <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all --> <!-- requests. Usually this filter mapping is defined first (before all others) to --> <!-- ensure that Shiro works in subsequent filters in the filter chain: --> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
spring-shiro-web.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 緩存管理器 使用Ehcache實現 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> </bean> <!-- 憑證匹配器 --> <bean id="credentialsMatcher" class="com.github.zhangkaitao.shiro.chapter12.credentials.RetryLimitHashedCredentialsMatcher"> <constructor-arg ref="cacheManager"/> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="2"/> <property name="storedCredentialsHexEncoded" value="true"/> </bean> <!-- Realm實現 --> <bean id="userRealm" class="com.github.zhangkaitao.shiro.chapter12.realm.UserRealm"> <property name="userService" ref="userService"/> <property name="credentialsMatcher" ref="credentialsMatcher"/> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> </bean> <!-- 會話ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 會話Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="180000"/> </bean> <!-- 會話DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 會話驗證調度器 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> <property name="sessionValidationInterval" value="1800000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- 會話管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="userRealm"/> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- 相當於調用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- 基於Form表單的身份驗證過濾器 --> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="usernameParam" value="username"/> <property name="passwordParam" value="password"/> <property name="loginUrl" value="/login.jsp"/> </bean> <!-- Shiro的Web過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login.jsp"/> <property name="unauthorizedUrl" value="/unauthorized.jsp"/> <property name="filters"> <util:map> <entry key="authc" value-ref="formAuthenticationFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /index.jsp = anon /unauthorized.jsp = anon /login.jsp = authc /logout = logout /** = user </value> </property> </bean> <!-- Shiro生命周期處理器--> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
二、常用shiro內置攔截器

1、NameableFilter
NameableFilter給Filter起個名字,如果沒有設置默認就是FilterName;當我們組裝攔截器鏈時會根據這個名字找到相應的攔截器實例;
2、OncePerRequestFilter
OncePerRequestFilter用於防止多次執行Filter;也就是說一次請求只會走一次攔截器鏈;另外提供enabled屬性,表示是否開啟該攔截器實例,默認enabled=true表示開啟,如果不想讓某個攔截器工作,可以設置為false即可。
3、ShiroFilter
ShiroFilter是整個Shiro的入口點,用於攔截需要安全控制的請求進行處理。
4、AdviceFilter
AdviceFilter提供了AOP風格的支持,類似於SpringMVC中的Interceptor.
5、PathMatchingFilter
PathMatchingFilter 提供了基於Ant風格的請求路徑匹配功能及攔截器參數解析的功能,如"roles[admin,user]"自動根據","分割解析到一個路徑參數配置並綁定到相應的路徑:
6、AccessControlFilter
AccessControlFilter提供了訪問控制的基礎功能;比如是否允許訪問/當訪問拒絕時如何處理等
7、默認攔截器
org.apache.shiro.web.filter.mgt.DefaultFilter 中的枚舉攔截器
public enum DefaultFilter { anon(AnonymousFilter.class), authc(FormAuthenticationFilter.class), authcBasic(BasicHttpAuthenticationFilter.class), authcBearer(BearerHttpAuthenticationFilter.class), logout(LogoutFilter.class), noSessionCreation(NoSessionCreationFilter.class), perms(PermissionsAuthorizationFilter.class), port(PortFilter.class), rest(HttpMethodPermissionFilter.class), roles(RolesAuthorizationFilter.class), ssl(SslFilter.class), user(UserFilter.class), invalidRequest(InvalidRequestFilter.class); }


8、自定義攔截器
通過自定義自己的攔截器可以擴展一些功能,諸如動態 url-角色/權限訪問控制的實現、根據 Subject 身份信息獲取用戶信息綁定到 Request(即設置通用數據)、驗證碼驗證、在線用戶信息的保存等等,因為其本質就是一個 Filter;所以 Filter 能做的它就能做.
(1)默認攔截器接口定義有三個方法
public interface Filter { //初始化 void init(FilterConfig var1) throws ServletException; //執行攔截邏輯 void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException; //攔截器銷毀回調方法 void destroy(); }
(2)根據需要繼承相應的父類 重寫相應方法即可
如果我們想進行訪問控制就可以繼承AccessControlFilter;
如果我們要添加一些通用數據我們可以直接繼承PathMatchingFilter;
三、攔截器鏈
Shiro對Servlet容器的FilterChain進行了代理,即ShiroFilter在繼續 Servlet 容器的 Filter鏈的執行之前,通過 ProxiedFilterChain 對 Servlet 容器的 FilterChain 進行了代理;即先走
Shiro 自己的 Filter 體系,然后才會委托給 Servlet 容器的 FilterChain 進行 Servlet 容器級別的 Filter 鏈執行; Shiro 的 ProxiedFilterChain 執行流程: 1、 先執行 Shiro 自己的 Filter 鏈; 2、再執行 Servlet 容器的 Filter 鏈(即原始的 Filter)。
1、攔截器鏈管理器
接口FilterChainManager,用於注冊 Filter;注冊 URL-Filter 的映射關系。
public interface FilterChainManager { //返回注冊當當前FilterChainManager過濾器 Map<String, Filter> getFilters(); //根據過濾器鏈名稱返回過濾器鏈 NamedFilterList getChain(String chainName); //校驗是否有可用的過濾器鏈 boolean hasChains(); //返回所有過濾器鏈的名稱 Set<String> getChainNames(); //輸入一個源過濾器鏈返回一個名字為chainName的代理過濾器鏈 //交給SimpleNamedFilterList代理最終包裝成一個ProxiedFilterChain返回 FilterChain proxy(FilterChain original, String chainName); //注冊過濾器 void addFilter(String name, Filter filter); //注冊過濾器 添加之前是否要初始化 void addFilter(String name, Filter filter, boolean init); //根據給定的名字和格式字符串定義創建過濾器鏈 void createChain(String chainName, String chainDefinition); //對於沒有匹配到的請求路徑 通常是/** 創建一個默認過濾器鏈 void createDefaultChain(String chainName); //注冊 URL-Filter 的映射關系 void addToChain(String chainName, String filterName); void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) throws ConfigurationException; //配置一個全局的過濾器集合用於所有請求路徑 這個集合將先於創建和設置過濾器鏈之前匹配 void setGlobalFilters(List<String> globalFilterNames) throws ConfigurationException; }
實現類DefaultFilterChainManager在構造器中會默認添加org.apache.shiro.web.filter.mgt.DefaultFilter中聲明的攔截器。
(1)shiro1.2注冊攔截器的流程?
應用啟動時:
監聽器org.apache.shiro.web.env.EnvironmentLoaderListener -->org.apache.shiro.web.env.EnvironmentLoader -->org.apache.shiro.web.env.IniWebEnvironment(默認是IniWebEnvironment,可以配置成自定義的類) -->默認加載classpath:shiro.ini文件進行解析 -->創建web安全管理器WebSecurityManager -->IniFilterChainResolverFactory::createInstance通過IniFilterChainResolverFactory工廠創建攔截器鏈處理器,默認是PathMatchingFilterChainResolver -->PathMatchingFilterChainResolver::getFilterChainManager獲取攔截器鏈管理器DefaultFilterChainManager -->IniFilterChainResolverFactory::buildChains創建過濾器鏈 -->IniFilterChainResolverFactory::registerFilters-->DefaultFilterChainManager::addFilter注冊過濾器存放到LinkedHashMap<String, Filter>結構 -->IniFilterChainResolverFactory::createChains-->DefaultFilterChainManager::createChain創建過濾器鏈 url部分是chainname存放到LinkedHashMap<String, NamedFilterList>結構
如果要自定義FilterChainResolver,可以自定義MyIniWebEnvironment.java繼承IniWebEnvironment來重寫上面邏輯
MyIniWebEnvironment.java:
package com.github.zhangkaitao.shiro.chapter8.web.env; import org.apache.shiro.util.ClassUtils; import org.apache.shiro.web.env.IniWebEnvironment; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter; import org.apache.shiro.web.filter.mgt.DefaultFilter; import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; import org.apache.shiro.web.filter.mgt.FilterChainResolver; import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; import javax.servlet.Filter; public class MyIniWebEnvironment extends IniWebEnvironment { @Override protected FilterChainResolver createFilterChainResolver() { //在此處擴展自己的FilterChainResolver //1、創建FilterChainResolver PathMatchingFilterChainResolver filterChainResolver = new PathMatchingFilterChainResolver(); //2、創建FilterChainManager DefaultFilterChainManager filterChainManager = new DefaultFilterChainManager(); //3、注冊Filter for(DefaultFilter filter : DefaultFilter.values()) { filterChainManager.addFilter(filter.name(), (Filter) ClassUtils.newInstance(filter.getFilterClass())); } //4、注冊URL-Filter的映射關系 filterChainManager.addToChain("/login.jsp", "authc"); filterChainManager.addToChain("/unauthorized.jsp", "anon"); filterChainManager.addToChain("/**", "authc"); filterChainManager.addToChain("/**", "roles", "admin"); //5、設置Filter的屬性 FormAuthenticationFilter authcFilter = (FormAuthenticationFilter)filterChainManager.getFilter("authc"); authcFilter.setLoginUrl("/login.jsp"); RolesAuthorizationFilter rolesFilter = (RolesAuthorizationFilter)filterChainManager.getFilter("roles"); rolesFilter.setUnauthorizedUrl("/unauthorized.jsp"); filterChainResolver.setFilterChainManager(filterChainManager); return filterChainResolver; } }
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="false"> <!--- shiro 1.2 --> <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> </listener> <context-param> <param-name>shiroEnvironmentClass</param-name> <param-value>com.github.zhangkaitao.shiro.chapter8.web.env.MyIniWebEnvironment</param-value> </context-param> <context-param> <param-name>shiroConfigLocations</param-name> <param-value>classpath:shiro.ini</param-value> </context-param> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
(2)shiro與spring整合注冊攔截器的流程?
結合一個整合Spring的web.xml配置來回顧一下web.xml各組件的啟動順序以及訪問時的執行順序:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="false"> <!-- Spring配置文件開始 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-beans.xml, classpath:spring-shiro-web.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Spring配置文件結束 --> <!-- shiro 安全過濾器 --> <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <async-supported>true</async-supported> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all --> <!-- requests. Usually this filter mapping is defined first (before all others) to --> <!-- ensure that Shiro works in subsequent filters in the filter chain: --> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
啟動順序:先執行監聽器public void contextInitialized(ServletContextEvent event)方法,然后執行攔截器Filter的public void init()方法
用戶訪問執行順序:先執行攔截器filter的doFilter方法,在執行Servlet的doGet/doPost/service方法;
流程:
Spring監聽器org.springframework.web.context.ContextLoaderListener::contextInitialized -->org.springframework.web.context.ContextLoader::initWebApplicationContext加載spring-beans.xml、spring-shiro-web.xml注冊bean到Spring容器上下文 -->spring-shiro-web.xml初始化和shiro相關的各個類,這里看一下Shiro的Web過濾器shiroFilter,實現類是org.apache.shiro.spring.web.ShiroFilterFactoryBean -->org.apache.shiro.spring.web.ShiroFilterFactoryBean::createInstance創建SecurityManager、FilterChainManager、PathMatchingFilterChainResolver,返回SpringShiroFilter實例,和原生ShiroFilter一樣要繼承AbstractShiroFilter -->org.apache.shiro.spring.web.ShiroFilterFactoryBean::createFilterChainManager在創建過濾器鏈管理器時將過濾器、過濾器鏈注冊到過濾器鏈管理器 攔截器:org.springframework.web.filter.DelegatingFilterProxy::init沒有重寫init 則執行父類的init方法 -->org.springframework.web.filter.GenericFilterBean::init -->org.springframework.web.filter.DelegatingFilterProxy::initFilterBean這一步是獲取web.xml中配置的<filter-name>內容 也就是shiroFilter 賦值給targetBeanName -->org.springframework.web.filter.DelegatingFilterProxy::initDelegate這一步很重要就是根據targetBeanName將之前注冊好的ShiroFilter賦值給DelegatingFilterProxy里的delegate
2、攔截器鏈處理器
接口FilterChainResolver:解析請求url,然后將URL和攔截器鏈管理器存放的攔截器鏈模式匹配,根據傳入原始的chain得到一個代理的chain,默認包裝成ProxiedFilterChain
public interface FilterChainResolver { FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain); }
默認實現類:PathMatchingFilterChainResolver:按照Ant風格路徑匹配的處理器
(1)shiro1.2執行攔截器鏈的流程?
web.xml配置的入口filter是org.apache.shiro.web.servlet.ShiroFilter,會執行doFilter方法,ShiroFilter本身沒有實現doFilter方法,則向上執行父類的doFilter方法: 請求url-->org.apache.shiro.web.servlet.ShiroFilter::doFilter方法 -->org.apache.shiro.web.servlet.OncePerRequestFilter::doFilter方法 -->org.apache.shiro.web.servlet.AbstractShiroFilter::doFilterInternal組裝Subject -->org.apache.shiro.subject.subject::execute -->org.apache.shiro.web.servlet.AbstractShiroFilter::executeChain -->org.apache.shiro.web.servlet.AbstractShiroFilter::getExecutionChain -->PathMatchingFilterChainResolver::getChain在這里根據請求地址獲取對應代理攔截器鏈 -->ProxiedFilterChain::doFilter依次執行攔截器鏈上的攔截器
(2)shiro與Spring整合執行攔截器鏈的流程?
攔截器:org.springframework.web.filter.DelegatingFilterProxy::doFilter -->org.springframework.web.filter.DelegatingFilterProxy::invokeDelegate 這里delegate就是注入的ShiroFilter -->org.apache.shiro.spring.web.ShiroFilterFactoryBean.SpringShiroFilter::doFilter沒有重寫 調用父類doFilter方法 -->org.apache.shiro.web.servlet.OncePerRequestFilter::doFilter方法 -->org.apache.shiro.web.servlet.AbstractShiroFilter::doFilterInternal組裝Subject -->org.apache.shiro.subject.subject::execute -->org.apache.shiro.web.servlet.AbstractShiroFilter::executeChain -->org.apache.shiro.web.servlet.AbstractShiroFilter::getExecutionChain -->PathMatchingFilterChainResolver::getChain在這里根據請求地址獲取對應代理攔截器鏈 -->ProxiedFilterChain::doFilter依次執行攔截器鏈上的攔截器
3、攔截器鏈
javax.servlet.FilterChain:攔截器鏈接口,里面就一個方法執行攔截器
public interface FilterChain { void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException; }
shiro里的實現:ProxiedFilterChain.java
public class ProxiedFilterChain implements FilterChain { private static final Logger log = LoggerFactory.getLogger(ProxiedFilterChain.class); private FilterChain orig; private List<Filter> filters; private int index = 0; //構造攔截器鏈 public ProxiedFilterChain(FilterChain orig, List<Filter> filters) { if (orig == null) { throw new NullPointerException("original FilterChain cannot be null."); } this.orig = orig; this.filters = filters; this.index = 0; } //依次執行list中攔截器 public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if (this.filters == null || this.filters.size() == this.index) { //當執行完攔截器鏈中所有攔截器后 然后執行元攔截器鏈中攔截器 this.orig.doFilter(request, response); } else { //順序執行攔截器鏈中的攔截器 this.filters.get(this.index++).doFilter(request, response, this); } } }
代碼及內容參考:張開濤-跟我學shiro
