zoukankan      html  css  js  c++  java
  • 【Shiro学习之四】shiro拦截器

    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>
    View Code

    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>
    View Code

    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>
    View Code

    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>
    View Code

    二、常用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;
    }
    View Code

    实现类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;
        }
    }
    View Code

    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>
    View Code

    (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>
    View Code

    启动顺序:先执行监听器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

     

  • 相关阅读:
    【Python第九篇】异步IO数据库队列缓存
    【Python第八篇】线程、进程及协程
    【Python第七篇】Socket网络编程
    实验五全部代码,ajax请求
    添加员工
    联级选择
    查询,利用jquery选择器
    列表、表格单选框
    注册
    聊天框
  • 原文地址:https://www.cnblogs.com/cac2020/p/13821528.html
Copyright © 2011-2022 走看看