spring boot整合redis實(shí)現(xiàn)shiro的分布式session共享的方法
我們知道,shiro是通過(guò)SessionManager來(lái)管理Session的,而對(duì)于Session的操作則是通過(guò)SessionDao來(lái)實(shí)現(xiàn)的,默認(rèn)的情況下,shiro實(shí)現(xiàn)了兩種SessionDao,分別為CachingSessionDAO和MemorySessionDAO,當(dāng)我們使用EhCache緩存時(shí),則是使用的CachingSessionDAO,不適用緩存的情況下,就會(huì)選擇基于內(nèi)存的SessionDao.所以,如果我們想實(shí)現(xiàn)基于Redis的分布式Session共享,重點(diǎn)在于重寫(xiě)SessionManager中的SessionDao。我們的重寫(xiě)代碼如下:
package com.chhliu.springboot.shiro.cache; import java.io.Serializable; import java.util.Collection; import java.util.concurrent.TimeUnit; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service @SuppressWarnings({ "rawtypes", "unchecked" }) public class RedisSessionDao extends AbstractSessionDAO { // Session超時(shí)時(shí)間,單位為毫秒 private long expireTime = 120000; @Autowired private RedisTemplate redisTemplate;// Redis操作類(lèi),對(duì)這個(gè)使用不熟悉的,可以參考前面的博客 public RedisSessionDao() { super(); } public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) { super(); this.expireTime = expireTime; this.redisTemplate = redisTemplate; } @Override // 更新session public void update(Session session) throws UnknownSessionException { System.out.println("===============update================"); if (session == null || session.getId() == null) { return; } session.setTimeout(expireTime); redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS); } @Override // 刪除session public void delete(Session session) { System.out.println("===============delete================"); if (null == session) { return; } redisTemplate.opsForValue().getOperations().delete(session.getId()); } @Override// 獲取活躍的session,可以用來(lái)統(tǒng)計(jì)在線人數(shù),如果要實(shí)現(xiàn)這個(gè)功能,可以在將session加入redis時(shí)指定一個(gè)session前綴,統(tǒng)計(jì)的時(shí)候則使用keys("session-prefix*")的方式來(lái)模糊查找redis中所有的session集合 public Collection<Session> getActiveSessions() { System.out.println("==============getActiveSessions================="); return redisTemplate.keys("*"); } @Override// 加入session protected Serializable doCreate(Session session) { System.out.println("===============doCreate================"); Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS); return sessionId; } @Override// 讀取session protected Session doReadSession(Serializable sessionId) { System.out.println("==============doReadSession================="); if (sessionId == null) { return null; } return (Session) redisTemplate.opsForValue().get(sessionId); } public long getExpireTime() { return expireTime; } public void setExpireTime(long expireTime) { this.expireTime = expireTime; } public RedisTemplate getRedisTemplate() { return redisTemplate; } public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } }
SessionDao實(shí)現(xiàn)完了之后,我們就需要將SessionDao加入SessionManager中了,代碼如下:
@Bean public DefaultWebSessionManager configWebSessionManager(){ DefaultWebSessionManager manager = new DefaultWebSessionManager(); manager.setCacheManager(cacheManager);// 加入緩存管理器 manager.setSessionDAO(sessionDao);// 設(shè)置SessionDao manager.setDeleteInvalidSessions(true);// 刪除過(guò)期的session manager.setGlobalSessionTimeout(sessionDao.getExpireTime());// 設(shè)置全局session超時(shí)時(shí)間 manager.setSessionValidationSchedulerEnabled(true);// 是否定時(shí)檢查session return manager; }
最后一步就是將SessionManager配置到SecurityManager中了
@Bean public SecurityManager securityManager(DefaultWebSessionManager webSessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 設(shè)置realm. securityManager.setRealm(myShiroRealm()); // 注入緩存管理器; securityManager.setCacheManager(cacheManager);// 這個(gè)如果執(zhí)行多次,也是同樣的一個(gè)對(duì)象; // session管理器 securityManager.setSessionManager(webSessionManager); //注入記住我管理器; securityManager.setRememberMeManager(rememberMeManager()); return securityManager; }
測(cè)試結(jié)果如下:
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
===============update================
==============doReadSession=================
==============doReadSession=================
===============update================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
權(quán)限配置-->MyShiroRealm.doGetAuthorizationInfo()
==============doReadSession=================
我們會(huì)發(fā)現(xiàn),當(dāng)一個(gè)頁(yè)面中存在多個(gè)資源的時(shí)候,會(huì)不停的調(diào)用doReadSession,update方法來(lái)讀取和更新session,目前這個(gè)問(wèn)題還沒(méi)有想到比較好的解決方案。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Shiro中session超時(shí)頁(yè)面跳轉(zhuǎn)的處理方式
- Spring Boot集成Shiro并利用MongoDB做Session存儲(chǔ)的方法詳解
- spring boot實(shí)戰(zhàn)教程之shiro session過(guò)期時(shí)間詳解
- Shiro+Redis實(shí)現(xiàn)登錄次數(shù)凍結(jié)的示例
- springboot整合shiro登錄失敗次數(shù)限制功能的實(shí)現(xiàn)代碼
- SpringBoot+Shiro學(xué)習(xí)之密碼加密和登錄失敗次數(shù)限制示例
- Shiro實(shí)現(xiàn)session限制登錄數(shù)量踢人下線功能
相關(guān)文章
RxJava的消息發(fā)送和線程切換實(shí)現(xiàn)原理
這篇文章主要介紹了RxJava的消息發(fā)送和線程切換實(shí)現(xiàn)原理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11Java詳細(xì)分析講解自動(dòng)裝箱自動(dòng)拆箱與Integer緩存的使用
裝箱就是把基本類(lèi)型轉(zhuǎn)換成包裝類(lèi),拆箱就是把包裝類(lèi)轉(zhuǎn)換成基本類(lèi)型,下面這篇文章主要給大家介紹Java中自動(dòng)裝箱、自動(dòng)拆箱與Integer緩存,需要的朋友可以參考下2022-04-04Spring?Boot?使用?Disruptor?做內(nèi)部高性能消息隊(duì)列
這篇文章主要介紹了Spring?Boot?使用?Disruptor?做內(nèi)部高性能消息隊(duì)列,工作中遇到項(xiàng)目使用Disruptor做消息隊(duì)列,對(duì)你沒(méi)看錯(cuò),不是Kafka,也不是rabbitmq。Disruptor有個(gè)最大的優(yōu)點(diǎn)就是快,還有一點(diǎn)它是開(kāi)源的哦,下面做個(gè)簡(jiǎn)單的記錄2022-06-06springMVC利用FastJson接口返回json數(shù)據(jù)相關(guān)配置詳解
本篇文章主要介紹了springMVC利用FastJson接口返回json數(shù)據(jù)相關(guān)配置詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Java?Valhalla?Project項(xiàng)目介紹
這篇文章主要介紹了Java?Valhalla?Project項(xiàng)目介紹,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Java 騰訊驗(yàn)證碼平臺(tái)使用實(shí)例
這篇文章主要介紹了Java 騰訊驗(yàn)證碼平臺(tái)使用實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02IDEA2023常用配置指南(JDK/系統(tǒng)設(shè)置等常用配置)
idea很強(qiáng)大,但是初次安裝默認(rèn)的有很多設(shè)置并不是滿足我們開(kāi)發(fā)的需要,下面這篇文章主要給大家介紹了關(guān)于IDEA2023常用配置(JDK/系統(tǒng)設(shè)置等常用配置)的相關(guān)資料,需要的朋友可以參考下2023-12-12java httpclient設(shè)置超時(shí)時(shí)間和代理的方法
這篇文章主要介紹了java httpclient設(shè)置超時(shí)時(shí)間和代理的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02詳解Java?ReentrantLock可重入,可打斷,鎖超時(shí)的實(shí)現(xiàn)原理
前面講解了ReentrantLock加鎖和解鎖的原理實(shí)現(xiàn),但是沒(méi)有闡述它的可重入、可打斷以及超時(shí)獲取鎖失敗的原理,本文就重點(diǎn)講解這三種情況,需要的可以了解一下2022-10-10