默認(rèn)Filter
name | class | effect |
---|---|---|
anon | AnonymousFilter | 都可以訪問(wèn) |
authc | FormAuthenticationFilter | 登錄之后才能進(jìn)行訪問(wèn)垫挨,不包括remember me |
user | UserFilter | 登錄用戶才可以訪問(wèn)靖榕,包含remember me |
logout | LogoutFilter | 立即登出登陸 |
...... |
自定義Filter
不同的登陸處理邏輯需要繼承不同類型的FIlter,比如,依賴web表單登陸的業(yè)務(wù)需要繼承FormAuthenticationFilter荡碾,未登錄的接口都會(huì)重定向到LoginUrl哀峻。自己處理登陸邏輯(比如token)的接口應(yīng)該繼承PassThruAuthenticationFilter,登陸失敗可以返回錯(cuò)誤碼月洛。不過(guò)所有的Filter只是認(rèn)證結(jié)果不一致,整個(gè)認(rèn)證的邏輯都是一致的。
Shiro的Filter統(tǒng)一交給ShiroFilterFactoryBean處理,配置文件看起來(lái)像這樣:
<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執(zhí)行流程
下面的分析流程我們以Post提交表單登陸為例(FormAuthenticationFilter)撵术。
通過(guò)第一篇,我們已經(jīng)知道shrio是如何從Spring MVC中接管web請(qǐng)求的话瞧,并且循環(huán)調(diào)用配置的filters嫩与,接下來(lái)先看一張filter執(zhí)行的概覽圖:
- 調(diào)用FormAuthenticationFilter.doFilter()方法,判斷當(dāng)前filter有沒(méi)有重復(fù)執(zhí)行;
- 調(diào)用doFilterInternal()交排,真正執(zhí)行fiter認(rèn)證流程划滋,執(zhí)行剩余的filter的鏈條,請(qǐng)求交給mvc的其他的filter埃篓;
- 調(diào)用preHandle方法处坪,返回值非常重要,決定當(dāng)前的請(qǐng)求要不要繼續(xù)走剩余的流程。
接下來(lái)稻薇,詳細(xì)分析preHandle方法的執(zhí)行流程:
1.先判斷當(dāng)前請(qǐng)求能否被處理
- 調(diào)用onPreHandle()方法
isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
2.1 isAccessAllowed()本質(zhì)是從線程局部變量獲取Subject對(duì)象嫂冻,判斷是否授權(quán)。如果是fasle塞椎,就會(huì)判斷是否不是登陸請(qǐng)求&&filter忽略(返回true)桨仿。因?yàn)榈顷懻?qǐng)求交給下一步處理
如果返回true,則表示當(dāng)前請(qǐng)求已經(jīng)登陸或不是登陸請(qǐng)求且是該Filter忽略的案狠,直接放行服傍。
2.2 當(dāng)?shù)谝徊椒祷豧alse時(shí)候,就會(huì)調(diào)用onAccessDenied()方法骂铁,處理未認(rèn)證的邏輯吹零。
先判斷是否為登陸請(qǐng)求,再判斷是否是登陸提交表單拉庵。是登陸提交表單灿椅,就之心executeLogin方法,否則就放行這個(gè)filter钞支,跳轉(zhuǎn)登陸頁(yè)面茫蛹。
過(guò)不是登陸請(qǐng)求,重定向到登陸頁(yè)面烁挟,返回false婴洼,filter結(jié)束本次請(qǐng)求。
-
executeLogin()執(zhí)行登陸請(qǐng)求方法
3.1 從登錄表單請(qǐng)求中獲取用戶名和密碼撼嗓,封裝為Token柬采,自定義Token可以重寫createToken()
3.2 獲取Shiro的上文對(duì)象
3.3 把包含登陸信息的token執(zhí)行登陸請(qǐng)求,具體調(diào)用Realm的登陸方法且警,上下文對(duì)象中就會(huì)存儲(chǔ)已經(jīng)成功認(rèn)證的信息粉捻,下次請(qǐng)求在2.1處就會(huì)直接放行。接下來(lái)會(huì)具體分析Realm的登陸流程斑芜。
3.4 登陸成功回調(diào)的方法
至此杀迹,認(rèn)證的閉環(huán)流程完成,3.4的重定向的請(qǐng)求到達(dá)2.1的isAccessAllowed()就會(huì)返回true押搪,filter直接放行這個(gè)請(qǐng)求树酪。
接下的章節(jié)會(huì)詳細(xì)分析登陸的subject.login()方法和Subject對(duì)象如何讓存儲(chǔ)登陸信息。