解析 Shiro-Spring 过滤器全流程

5 篇文章 0 订阅
2 篇文章 0 订阅

对于Spring 集成 Shiro,一般要求配置一个如下的Filter(web.xml)

<!-- 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>
    <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>
  • DelegatingFilterProxy 这个类是Spring针对Filter的委托代理模式的体现,它不是真正的目标Filter,而是在每次拦截到请求时,从Spring容器中查找名字为(即上述的shiroFilter)的Bean,并将请求委托于它,源码可见DelegatingFilterProxy.doFilter(…)
  • 值得一提的是,如果容器内的目标Bean实现了org.springframework.beans.factory.FactoryBean接口,则表示该Bean是一个工厂类,此时并非直接返回它本身,而是调用工厂方法getObject()来生产一个Bean,并提供给调用者

让我们查阅Spring配置(applicationContext.xml),寻找名字为shiroFilter的Bean

<!--Shiro 核心过滤器/拦截器,拦截一切请求-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- override these for application-specific URLs if you like:
    <property name="loginUrl" value="/login.jsp"/>
    <property name="successUrl" value="/home.jsp"/>
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/> -->
    <property name="loginUrl" value="/user/login"/>
    <property name="successUrl" value="/home.jsp"/>
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean  -->
    <!-- defined will be automatically acquired and available via its beanName in chain        -->
    <!-- definitions, but you can perform instance overrides or name aliases here if you like: -->
    <!-- <property name="filters">
        <util:map>
            <entry key="anAlias" value-ref="someFilter"/>
        </util:map>
    </property> -->
    <property name="filterChainDefinitions">
        <value>
            # some example chain definitions:
            #/admin/** = authc, roles[admin]
            #/docs/** = authc, perms[document:read]
            #/** = authc
            # more URL-to-FilterChain definitions here

            #开始配置
            /** = anon

        </value>
    </property>
</bean>

ShiroFilterFactoryBean 实现了FactoryBean接口,是一个工厂Bean,按照之前所述,它会调用getObject()来提供真正的目标Filter ,查看源码

public Object getObject() throws Exception {
    if (instance == null) {
        instance = createInstance();
    }
    return instance;
}

protected AbstractShiroFilter createInstance() throws Exception {

    //......

    //初始化过滤器链
    FilterChainManager manager = createFilterChainManager();

    //......

    return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}

可以看到最终委托的目标Filter是私有内部类ShiroFilterFactoryBean.SpringShiroFilter


在SpringShiroFilter的构建过程中,即ShiroFilterFactoryBean.createInstance()代码中有这么一句

FilterChainManager manager = createFilterChainManager();
  • 这是在初始化Shiro过滤器链,SpringShiroFilter主要充当管理者,先将真正干活的多个过滤器收集起来,并拼接成过滤器链(解析器),而后在每次请求转发时根据各种环境判断转发(转发给内部管理的shiro过滤器链,或转发给Tomcat的过滤器链),一般针对每一个请求,Shiro过滤器链至少能处理一次(实际逻辑更复杂)
  • 根据上诉代码不断深入源码,可以查看到默认配置/添加的11个默认Filter 分别是
public enum DefaultFilter {

    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.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);

    private final Class<? extends Filter> filterClass;

    private DefaultFilter(Class<? extends Filter> filterClass) {
        this.filterClass = filterClass;
    }

    //......
}
  • 看名字就很清楚
    • anon用于非验证的请求,直接转发给Tomcat过滤器链而不受shiro过滤器链的影响
    • authc用于用户认证,只能已登录有效的用户才能进入下一个Filter
    • logout用于注销,一旦注销成功(清除用户信息、会话信息等),一般会重定向注销页面的url(302响应),可根据需要重写为返回json格式串
    • perms用于访问控制(权限验证),只有具备权限才能进入下一个Filter
    • roles用于访问控制(角色验证),只有属于某个角色才能进入下一个Filter

通过开头的Spring配置(applicationContext.xml),我们可以很轻易地改写shiro过滤器链(覆盖、添加、重命名等),以达到自己的需求(例如改写成Restful风格,实现JWT认证等)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值