Shiro框架:缓存、session会话、自定义FormAuthenticationFilter、RemenberMe
上篇的地址:https://blog.csdn.net/a745233700/article/details/81350191
?
一、Shiro緩存--cacheManager:
針對(duì)上一篇授權(quán)的時(shí)候頻繁查詢數(shù)據(jù)庫(kù)的問(wèn)題,可以使用shiro緩存來(lái)解決。
1、緩存流程:
(1)shiro中提供了對(duì)認(rèn)證信息和授權(quán)信息的緩存。shiro默認(rèn)是關(guān)閉認(rèn)證信息緩存的,對(duì)于授權(quán)信息的緩存shiro默認(rèn)開(kāi)啟的。我們主要研究授權(quán)信息緩存,因?yàn)槭跈?quán)的數(shù)據(jù)量大。
(2)流程:用戶認(rèn)證通過(guò)之后,該用戶第一次授權(quán);調(diào)用realm查詢數(shù)據(jù)庫(kù)。該用戶第二次授權(quán),不調(diào)用realm查詢數(shù)據(jù)庫(kù),直接從緩存中取出授權(quán)信息(權(quán)限標(biāo)識(shí)符)。
2、配置shiro緩存:
(1)導(dǎo)入依賴:
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.2.3</version> </dependency>(2)配合cacheManager:
<!-- securityManager安全管理器 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="customRealm"></property><!-- 注入緩存管理器 --><property name="cacheManager" ref="cacheManager"></property></bean><!-- 緩存管理器 --><bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"></property></bean>(3)編寫緩存相關(guān)信息文件:shiro-ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"><!--diskStore:緩存數(shù)據(jù)持久化的目錄 地址 --><diskStore path="D:\test\shiro\ehcache" /><defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000"eternal="false" overflowToDisk="false" diskPersistent="false"timeToIdleSeconds="120"timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"></defaultCache> </ehcache>至此,Shiro的緩存就配置好了。
3、緩存清空:
(1)如果用戶正常退出,緩存自動(dòng)清空;如果用戶非正常退出,緩存也自動(dòng)清空。
如果修改了用戶的權(quán)限,而用戶不退出系統(tǒng),修改的權(quán)限無(wú)法立即生效。
(2)手動(dòng)進(jìn)行編程的實(shí)現(xiàn):
在權(quán)限修改后,調(diào)用realm的clearCache方法清除緩存。
下邊的代碼正常開(kāi)發(fā)時(shí)要放在service中調(diào)用。
在service中,權(quán)限修改后調(diào)用realm的方法。
在realm中定義clearCached方法:
//清除緩存代碼public void clearCached() {PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();super.clearCache(principals);}(3)測(cè)試清除緩存的controller方法:
@Controller public class ClearShiroCacheTest {//注入realm@Autowiredprivate CustomRealm customRealm;@RequestMapping("/clearShiroCache")public String clearShiroCache(){//清除緩存,在正常開(kāi)發(fā)中要在servicecustomRealm.clearCached();return "success";} }4、shiro緩存說(shuō)明:
(1)CacheManagerAware接口:
Shiro內(nèi)部相關(guān)組件(DefaultSecurityManager)會(huì)自動(dòng)檢測(cè)相應(yīng)的對(duì)象(如Realm)是否實(shí)現(xiàn)了CacheManagerAware并自動(dòng)注入了CacheManager。
(2)Realm緩存:Shiro提供了CachingRealm,其實(shí)現(xiàn)了CacheManagerAware接口,提供了一些基礎(chǔ)實(shí)現(xiàn);并且,AuthenticationRealm和AuthorizingRealm也分別提供了AuthenticationInfo和AutuorizationInfo信息的緩存。
?
?
二、Shiro會(huì)話--sessionManager:
SSM和Shiro整合后,使用shiro的session管理,shiro提供sessionDao操作會(huì)話數(shù)據(jù)。
1、Shiro提供了完整的企業(yè)級(jí)會(huì)話管理功能,不依賴于底層容器(如web容器tomcat),不管JavaSE還是JavaEE環(huán)境都可以使用,提供了會(huì)話管理、會(huì)話事件監(jiān)聽(tīng)、會(huì)話存儲(chǔ)/持久化、容器無(wú)關(guān)的集群、失效/過(guò)期支持、對(duì)Web 的透明支持、SSO 單點(diǎn)登錄的支持等特性。
2、配置sessionManager:
<!-- securityManager安全管理器 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="customRealm"></property><!-- 注入緩存管理器 --><property name="cacheManager" ref="cacheManager"></property><!-- 注入session管理器 --><property name="sessionManager" ref="sessionManager"></property></bean><!-- 會(huì)話管理器 --><bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"><!-- session的失效時(shí)間,單位毫秒 --><property name="globalSessionTimeout" value="600000"></property><!-- 刪除失效的session --><property name="deleteInvalidSessions" value="true"></property></bean>3、會(huì)話相關(guān)的API:
(1)Subject.getSession():即可獲取會(huì)話;其等價(jià)于Subject.getSession(true),即如果當(dāng)前沒(méi)有創(chuàng)建Session 對(duì)象會(huì)創(chuàng)建一個(gè);Subject.getSession(false),如果當(dāng)前沒(méi)有創(chuàng)建Session 則返回null。
(2)session.getId():獲取當(dāng)前會(huì)話的唯一標(biāo)識(shí)。
(3)session.getHost():獲取當(dāng)前Subject的主機(jī)地址
(4)session.getTimeout() & session.setTimeout(毫秒):獲取/設(shè)置當(dāng)前Session的過(guò)期時(shí)間。
(5)session.getStartTimestamp() & session.getLastAccessTime():獲取會(huì)話的啟動(dòng)時(shí)間及最后訪問(wèn)時(shí)間;如果是JavaSE應(yīng)用需要自己定期調(diào)用session.touch() 去更新最后訪問(wèn)時(shí)間;如果是Web 應(yīng)用,每次進(jìn)入ShiroFilter都會(huì)自動(dòng)調(diào)用session.touch() 來(lái)更新最后訪問(wèn)時(shí)間。
(6)session.touch() & session.stop():更新會(huì)話最后訪問(wèn)時(shí)間及銷毀會(huì)話;當(dāng)Subject.logout()時(shí)會(huì)自動(dòng)調(diào)用stop 方法來(lái)銷毀會(huì)話。如果在web中,調(diào)用HttpSession. invalidate() 也會(huì)自動(dòng)調(diào)用ShiroSession.stop方法進(jìn)行銷毀Shiro的會(huì)話。
(7)session.setAttribute(key, val) & session.getAttribute(key) & session.removeAttribute(key):設(shè)置/獲取/刪除會(huì)話屬性;在整個(gè)會(huì)話范圍內(nèi)都可以對(duì)這些屬性進(jìn)行操作。
?
?
三、自定義FormAuthenticationFilter:
1、需求:使用自定義的FormAuthenticationFilter實(shí)現(xiàn)驗(yàn)證碼功能。
(1)shiro使用FormAuthenticationFilter進(jìn)行表單認(rèn)證,驗(yàn)證校驗(yàn)的功能應(yīng)該加在FormAuthenticationFilter中,在認(rèn)證之前進(jìn)行驗(yàn)證碼校驗(yàn)。
(2)需要寫FormAuthenticationFilter的子類,繼承FormAuthenticationFilter,改寫它的認(rèn)證方法,在認(rèn)證之前進(jìn)行驗(yàn)證碼校驗(yàn)。
2、自定義FormAuthenticationFilter:
/*** Description:自定義FormAuthenticationFilter,認(rèn)證之前實(shí)現(xiàn) 驗(yàn)證碼校驗(yàn) */ public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {//原FormAuthenticationFilter的認(rèn)證方法@Overrideprotected boolean onAccessDenied(ServletRequest request,ServletResponse response) throws Exception {//在這里進(jìn)行驗(yàn)證碼的校驗(yàn)//從session獲取正確驗(yàn)證碼HttpServletRequest httpServletRequest = (HttpServletRequest) request;HttpSession session =httpServletRequest.getSession();//取出session的驗(yàn)證碼(正確的驗(yàn)證碼)String validateCode = (String) session.getAttribute("validateCode");//取出頁(yè)面的驗(yàn)證碼//輸入的驗(yàn)證和session中的驗(yàn)證進(jìn)行對(duì)比 String randomcode = httpServletRequest.getParameter("randomcode");if(randomcode!=null && validateCode!=null && !randomcode.equals(validateCode)){//如果校驗(yàn)失敗,將驗(yàn)證碼錯(cuò)誤失敗信息,通過(guò)shiroLoginFailure設(shè)置到request中httpServletRequest.setAttribute("shiroLoginFailure", "randomCodeError");//拒絕訪問(wèn),不再校驗(yàn)賬號(hào)和密碼 return true; }return super.onAccessDenied(request, response);} }3、配置自定義FormAuthenticationFilter:
<!-- 自定義form認(rèn)證過(guò)濾器 --><!-- 基于form表單的身份驗(yàn)證過(guò)濾器,不配置也會(huì)注冊(cè)此過(guò)濾器,不過(guò)表單中的用戶賬號(hào)、密碼和loginUrl將采用默認(rèn)值,建議配置 --><bean id="formAuthenticationFilter" class="com.zwp.shiro.CustomFormAuthenticationFilter"><!-- 表單中賬戶的input名稱 --><property name="usernameParam" value="username"></property><!-- 表單中密碼的input名稱 --><property name="passwordParam" value="password"></property></bean>4、在登陸頁(yè)面添加驗(yàn)證碼:
5、在filter配置匿名訪問(wèn)驗(yàn)證碼的jsp:
至此,使用自定義FormAuthenticationFilter實(shí)現(xiàn)驗(yàn)證碼功能就完成了。
?
?
四、記住我--RememberMe:
1、概述:Shiro提供了記住我(RememberMe)的功能,比如訪問(wèn)如淘寶等一些網(wǎng)站時(shí),關(guān)閉了瀏覽器,下次再打開(kāi)時(shí)還是能記住你是誰(shuí),下次訪問(wèn)時(shí)無(wú)需再登錄即可訪問(wèn),基本流程如下:
(1)首先在登錄頁(yè)面選中RememberMe然后登錄成功;如果是瀏覽器登錄,一般會(huì)把RememberMe的Cookie 寫到客戶端并保存下來(lái);
(2)關(guān)閉瀏覽器再重新打開(kāi);會(huì)發(fā)現(xiàn)瀏覽器還是記住你的;
(3)訪問(wèn)一般的網(wǎng)頁(yè)服務(wù)器端還是知道你是誰(shuí),且能正常訪問(wèn);
(4)但是比如我們?cè)L問(wèn)淘寶時(shí),如果要查看我的訂單或進(jìn)行支付時(shí),此時(shí)還是需要再進(jìn)行身份認(rèn)證的,以確保當(dāng)前用戶還是你。
2、認(rèn)證和記住我:
(1)subject.isAuthenticated() 表示用戶進(jìn)行了身份驗(yàn)證登錄的,即使有Subject.login進(jìn)行了登錄;
(2)subject.isRemembered():表示用戶是通過(guò)記住我登錄的,此時(shí)可能并不是真正的你(如你的朋友使用你的電腦,或者你的cookie 被竊取)在訪問(wèn)的。
(3)兩者二選一,即subject.isAuthenticated()==true,則subject.isRemembered()==false;反之一樣。
3、實(shí)現(xiàn):
用戶登陸選擇“記住我",本次登陸成功會(huì)向cookie寫身份信息,下次登陸從cookie中取出身份信息實(shí)現(xiàn)自動(dòng)登陸。
(1)用戶身份實(shí)現(xiàn)java.io.Seriializable接口:
向cookie記錄身份信息,需要用戶身份信息對(duì)象實(shí)現(xiàn)序列化接口,如下:
/*** 用戶身份信息,存入session,由于tomcat將session序列化在本地硬盤上,所以使用Serializable接口*/ public class ActiveUser implements java.io.Serializable {private String userid;//用戶id(主鍵)private String usercode;// 用戶賬號(hào)private String username;// 用戶名稱private List<SysPermission> menus;// 菜單private List<SysPermission> permissions;// 權(quán)限//下面省略set和get方法 }(2)配置rememberMeManager:
<!-- securityManager安全管理器 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="customRealm"></property><!-- 注入緩存管理器 --><property name="cacheManager" ref="cacheManager"></property><!-- 注入session管理器 --><property name="sessionManager" ref="sessionManager"></property><!-- 記住我,注入 --><property name="rememberMeManager" ref="rememberMeManager"></property></bean><!-- rememberMeManager管理器,取出cookie生成用戶信息 --><bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"><property name="cookie" ref="rememberMeCookie"></property></bean><!-- 記住我cookie --><bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"><!-- remenberMe是cookie的名字 --><constructor-arg value="rememberMe"></constructor-arg><!-- remenberMe的cookie的生效時(shí)間是30天 --><property name="maxAge" value="2592000"></property></bean>(3)登陸頁(yè)面:
(4)配置rememberMe的名稱:
(5)測(cè)試:
勾選“記住我”登陸后,查看cookie是否有rememberMe:
(6)使用UserFilter:
如果設(shè)置記住我,下次訪問(wèn)某些url時(shí)可以不用登陸。將記住我即可訪問(wèn)的地址配置讓UserFilter攔截。
至此,Shiro的rememberMe就配置完成了。
(7)remenberMe使用建議:
①訪問(wèn)一般網(wǎng)頁(yè):如個(gè)人在主頁(yè)之類的,我們使用user 攔截器即可,user 攔截器只要用戶登錄(isRemembered() || isAuthenticated())過(guò)即可訪問(wèn)成功;
②訪問(wèn)特殊網(wǎng)頁(yè):如我的訂單,提交訂單頁(yè)面,我們使用authc攔截器即可,authc攔截器會(huì)判斷用戶是否是通過(guò)Subject.login(isAuthenticated()==true)登錄的,如果是才放行,否則會(huì)跳轉(zhuǎn)到登錄頁(yè)面叫你重新登錄。
?
?
總結(jié)
以上是生活随笔為你收集整理的Shiro框架:缓存、session会话、自定义FormAuthenticationFilter、RemenberMe的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SSM整合Shiro进行登陆认证和授权详
- 下一篇: 在eclipse使用git管理项目工程代