美文网首页Shiro
Shiro源码分析系列:02.Filters的执行流程

Shiro源码分析系列:02.Filters的执行流程

作者: 城南码农 | 来源:发表于2019-04-29 13:03 被阅读0次

    默认Filter

    name class effect
    anon AnonymousFilter 都可以访问
    authc FormAuthenticationFilter 登录之后才能进行访问,不包括remember me
    user UserFilter 登录用户才可以访问,包含remember me
    logout LogoutFilter 立即登出登陆
    ......

    自定义Filter

    不同的登陆处理逻辑需要继承不同类型的FIlter,比如,依赖web表单登陆的业务需要继承FormAuthenticationFilter,未登录的接口都会重定向到LoginUrl。自己处理登陆逻辑(比如token)的接口应该继承PassThruAuthenticationFilter,登陆失败可以返回错误码。不过所有的Filter只是认证结果不一致,整个认证的逻辑都是一致的。
    Shiro的Filter统一交给ShiroFilterFactoryBean处理,配置文件看起来像这样:

     <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="securityManager" ref="securityManager"/>
            <property name="filters">
                <util:map>
                    <entry key="jwt">
                        <bean class="**********.JwtAuthenticationFilter">
                            <property name="loginUrl" value="/jwtlogin"/>
                            <property name="successUrl" value="/mall/mallManage.sc.sc"/>
                        </bean>
                    </entry>
                    <entry key="authc">
                        <bean class="***********.WebFormAuthenticationFilter">
                            <property name="usernameParam" value="username"/>
                            <property name="passwordParam" value="password"/>
                            <property name="checkCode" value="checkCode"/>
                            <property name="pageId" value="pageId"/>
                            <property name="failureKeyAttribute" value="shiroLoginFailure"/>
                            <property name="loginUrl" value="/login.sc"/>
                            <property name="successUrl" value="/index.sc"/>
                        </bean>
                    </entry>
                    <!--<entry key="checkCode" value-ref="checkCodeAuthenticationFilter"/>-->
                </util:map>
            </property>
            <property name="filterChainDefinitionMap">
                <util:map>
                    <entry key="/MemberCameraPoint/menberCameraPoin" value="anon"/>
                    <entry key="/assets/**" value="anon"/>
                    <entry key="/logout" value="logout"/>
                    <entry key="/mobile/**" value="anon"/>
                    <entry key="/wxlogin/**" value="anon"/>
                    <entry key="/packageGoods/**" value="anon"/>
                    <!--
                    <entry key="/php/**" value="anon"/>
                    <entry key="/api/**" value="anon"/>
                    -->
                    <entry key="/ueditor/**" value="anon"/>
                    <entry key="/swagger-ui.html**" value="anon"/>
                    <entry key="/redis/loadData" value="anon"/>
                    <entry key="/pay/alipay/refund/notify" value="anon"/>
                    <entry key="/act/**" value="anon"/>
                    <entry key="/shutdown" value="anon"/>
                    <entry key="/webjars/**" value="anon"/>
                    <entry key="/swagger-resources/**" value="anon"/>
                    <entry key="/v2/api-docs" value="anon"/>
                    <entry key="/bindCheckCode" value="anon"/>
                    <entry key="/gotoBindCheckCode" value="anon"/>
                    <entry key="/erpcoupon/publishCampInfo" value="anon"/>
                    <entry key="/system/tools/**" value="anon"/>
                    <!--<entry key="/login.sc" value="checkCode,authc"/>-->
                    <entry key="/jwtlogin/**" value="jwt"/>
                    <entry key="/**" value="authc"/>
                </util:map>
            </property>
        </bean>
    

    Filter执行流程

    下面的分析流程我们以Post提交表单登陆为例(FormAuthenticationFilter)。
    通过第一篇,我们已经知道shrio是如何从Spring MVC中接管web请求的,并且循环调用配置的filters,接下来先看一张filter执行的概览图:


    2.0.Filter执行流程.jpg
    1. 调用FormAuthenticationFilter.doFilter()方法,判断当前filter有没有重复执行;
    2. 调用doFilterInternal(),真正执行fiter认证流程,执行剩余的filter的链条,请求交给mvc的其他的filter;
    3. 调用preHandle方法,返回值非常重要,决定当前的请求要不要继续走剩余的流程。

    接下来,详细分析preHandle方法的执行流程:
    1.先判断当前请求能否被处理


    image.png
    1. 调用onPreHandle()方法
    isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
    

    2.1 isAccessAllowed()本质是从线程局部变量获取Subject对象,判断是否授权。如果是fasle,就会判断是否不是登陆请求&&filter忽略(返回true)。因为登陆请求交给下一步处理
    如果返回true,则表示当前请求已经登陆或不是登陆请求且是该Filter忽略的,直接放行。
    2.2 当第一步返回false时候,就会调用onAccessDenied()方法,处理未认证的逻辑。


    image.png

    先判断是否为登陆请求,再判断是否是登陆提交表单。是登陆提交表单,就之心executeLogin方法,否则就放行这个filter,跳转登陆页面。
    过不是登陆请求,重定向到登陆页面,返回false,filter结束本次请求。

    1. executeLogin()执行登陆请求方法


      image.png

      3.1 从登录表单请求中获取用户名和密码,封装为Token,自定义Token可以重写createToken()
      3.2 获取Shiro的上文对象
      3.3 把包含登陆信息的token执行登陆请求,具体调用Realm的登陆方法,上下文对象中就会存储已经成功认证的信息,下次请求在2.1处就会直接放行。接下来会具体分析Realm的登陆流程。
      3.4 登陆成功回调的方法


      image.png
      至此,认证的闭环流程完成,3.4的重定向的请求到达2.1的isAccessAllowed()就会返回true,filter直接放行这个请求。
      接下的章节会详细分析登陆的subject.login()方法和Subject对象如何让存储登陆信息。

    相关文章

      网友评论

        本文标题:Shiro源码分析系列:02.Filters的执行流程

        本文链接:https://www.haomeiwen.com/subject/dfytgqtx.html