社区
高性能WEB开发
帖子详情
用 Spring+Shiro+Redis 实现服务器集群会话管理
yk624459085
2014-02-19 04:15:40
怎样用 Spring+Shiro+Redis 实现服务器集群会话管理呢? 最好能贴上代码。
...全文
28949
4
打赏
收藏
用 Spring+Shiro+Redis 实现服务器集群会话管理
怎样用 Spring+Shiro+Redis 实现服务器集群会话管理呢? 最好能贴上代码。
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
4 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
小丑哥_V5
2015-04-14
打赏
举报
回复
兄弟你可以到我博客看看shiro的文章吧,都有你想要的了
zyiqibook
2015-03-05
打赏
举报
回复
shiro redis集群 示例项目源码贡献
,抱歉,来晚了,因为我也涉及到了这一块,弄了这么一篇文章出来,项目拿来即用
gemcube
2015-01-17
打赏
举报
回复
别人要redis的,你给贴个zookeeper的,还是抄的不全
VIP_吴志国
2014-02-20
打赏
举报
回复
第一步:配置WEB.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> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 第二步:SHIRO整合SPRING配置 applicationContext-shiro.xml 伪代码: <!--Session集群配置--> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="3600000"/> <property name="sessionDAO" ref="zkShiroSessionDAO"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionIdCookie" ref="wapsession"/> </bean> <!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID, 当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! --> <bean id="wapsession" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg name="name" value="WAPSESSIONID"/> </bean> <!-- 定时清理僵尸session,Shiro会启用一个后台守护线程定时执行清理操作 用户直接关闭浏览器造成的孤立会话 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler"> <property name="interval" value="3600000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!--由zk做session存储容器--> <bean id="zkShiroSessionDAO" class="b2gonline.incometaxexamine._systembase.shiro.ZKShiroSessionDAO"> <!--使用内存缓存登录用户信息,一次获取用户登录信息后缓存到内存减少Shiro大量的读取操作,用户退出或超时后自动清除--> <constructor-arg name="useMemCache" value="true"/> <property name="zookeeperTemplate" ref="zookeeperTemplate"/> <property name="shiroSessionZKPath" value="/SHIROSESSIONS"/> <property name="sessionPrefix" value="session-"/> </bean> <!-- SHIRO安全接口 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> ... <property name="sessionManager" ref="sessionManager"/> </bean> 第三步:Zookeeper对Shiro-SessionDao实现类 ZKShiroSessionDAO.JAVA伪代码: import bgonline.foundation.hadoop.zk.IZookeeperTemplate; import bgonline.foundation.hadoop.zk.ZNode; import org.apache.shiro.cache.AbstractCacheManager; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.cache.MapCache; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import org.apache.shiro.session.mgt.eis.CachingSessionDAO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.SerializationUtils; import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * ZOOKEEPER实现SHIRO集群SESSION存储 * * @author aliencode * @date 13-7-10 */ public class ZKShiroSessionDAO extends CachingSessionDAO { public ZKShiroSessionDAO() { } private boolean useMemCache = false; /** * SESSION ZK DAO 实例 * 如果开户缓存 * 用户登录时自动缓存, 用户登录超时自动删除 * 由于shiro的cacheManager是全局的, 所以这里使用setActiveSessionsCache直接设置Cache来本地缓存, 而不使用全局zk缓存. * 由于同一用户可能会被路由到不同服务器,所以在doReadSession方法里也做了缓存增加. * * @param useMemCache 是否使用内存缓存登录信息 */ public ZKShiroSessionDAO(boolean useMemCache) { this.useMemCache = useMemCache; if (useMemCache) { setActiveSessionsCache( new MapCache<>(this.ACTIVE_SESSION_CACHE_NAME, new ConcurrentHashMap<Serializable, Session>()) ); } } Logger logger = LoggerFactory.getLogger(this.getClass()); /** * ZK操作类 */ private IZookeeperTemplate zookeeperTemplate; /** * 缓存根路径, 结尾不加/ */ private String shiroSessionZKPath = "/SHIROSESSIONS"; /** * 缓存项前缀 */ private String sessionPrefix = "session-"; /** * 设置Shiro Session 前缀 默认 session- * * @param sessionPrefix */ public void setSessionPrefix(String sessionPrefix) { this.sessionPrefix = sessionPrefix; } public void setZookeeperTemplate(IZookeeperTemplate zookeeperTemplate) { this.zookeeperTemplate = zookeeperTemplate; } /** * 设置Shiro在ZK服务器存放根路径 * * @param shiroSessionZKPath 默认值:/SHIROSESSIONS/ */ public void setShiroSessionZKPath(String shiroSessionZKPath) { this.shiroSessionZKPath = shiroSessionZKPath; } /** * session更新 * * @param session * @throws UnknownSessionException */ @Override public void update(Session session) throws UnknownSessionException { if (session == null || session.getId() == null) { logger.error("session argument cannot be null."); } saveSession(session, "update"); } @Override protected void doUpdate(Session session) { } /** * session删除 * * @param session */ @Override public void delete(Session session) { if (session == null || session.getId() == null) { logger.error("session argument cannot be null."); } logger.debug("delete session for id: {}", session.getId()); zookeeperTemplate.deleteNode(getPath(session.getId())); if (useMemCache) { this.uncache(session); } } @Override protected void doDelete(Session session) { } /** * 获取当前活跃的session, 当前在线数量 * * @return */ @Override public Collection<Session> getActiveSessions() { ZNode zNode = new ZNode(); zNode.setPath(shiroSessionZKPath); Set<Session> sessions = new HashSet<Session>(); //读取所有SessionID , 返回形如: session-9e3b5707-fa80-4d32-a6c9-f1c3685263a5 List<String> ss = zookeeperTemplate.getChildren(zNode); for (String id : ss) { if (id.startsWith(sessionPrefix)) { String noPrefixId = id.replace(sessionPrefix, ""); Session session = doReadSession(noPrefixId); if (session != null) sessions.add(session); } } logger.debug("shiro getActiveSessions. size: {}", sessions.size()); return sessions; } /** * 创建session, 用户登录 * * @param session * @return */ @Override protected Serializable doCreate(Session session) { Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); saveSession(session, "create"); return sessionId; } /** * session读取 * * @param id * @return */ @Override protected Session doReadSession(Serializable id) { if (id == null) { logger.error("id is null!"); return null; } logger.debug("doReadSession for path: {}", getPath(id)); Session session; byte[] byteData = zookeeperTemplate.getData(getPath(id)).getByteData(); if (byteData != null && byteData.length > 0) { session = (Session) SerializationUtils.deserialize(byteData); if (useMemCache) { this.cache(session, id); logger.debug("doReadSession for path: {}, add cached !", getPath(id)); } return session; } else { return null; } } /** * 生成全路径 * * @param sessID * @return */ private String getPath(Serializable sessID) { return shiroSessionZKPath + '/' + sessionPrefix + sessID.toString(); } /** * session读取或更新 * * @param session * @param act update/save */ private void saveSession(Session session, String act) { Serializable sessionId = session.getId(); ZNode sessionNode = new ZNode(); sessionNode.setByteData(SerializationUtils.serialize(session)); sessionNode.setPath(getPath(sessionId)); logger.debug("save session for id: {}, act: {}", sessionId, act); if (act == "update") zookeeperTemplate.setData(sessionNode); else zookeeperTemplate.createNode(sessionNode); } }
spring
boot+
shiro
+
redis
整合
spring
boot 整合
shiro
的认证,
redis
实现
session共享案例
SSM+
shiro
+
redis
根据ssm整合的
shiro
权限框架和
redis
缓存搭建起来的框架
spring
+
shiro
+
redis
spring
+
shiro
+r edis
实现
的简单demo,适合初学者使用
基于ssm+
shiro
+
redis
+nginx tomcat
服务器
集群
管理
项目源码+项目说明.zip
【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 3、本资源作为“参考资料”如果需要
实现
其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于ssm+
shiro
+
redis
+nginx tomcat
服务器
集群
管理
项目源码+项目说明.zip Introduction ==== 1.搭建一个最简洁,模块划分最明确的ssm+swargger+
shiro
+
redis
+nginx整合项目,采用maven作为构建工具,在有新项目开发时可以借助此demo快速构建项目
2.
实现
shiro
的授权信息缓存到
redis
数据库,减少关系数据库访问压力
3.
实现
session共享到
redis
,
实现
多
服务器
集群
方案
4.配置文档中包含丰富的注释,搭建思路清晰的ssm项目框架
5.项目中的所有细节都会按照企业级开发的标准,展示如何遵循代码规范以及类文件doc注释的编写。
6.采用RESTFul的controller接口,展示RESTFul风格的API编写(
shiro
基于url的权限拦截与RESTFul API兼容性不好,后期可能会改写
shiro
以匹配RESTFul)
7.Junit单元测试,展示如何正确的使用Junit单元测试验证自己接口代码的健壮性
涉及到的技术 ====
spring
mvc+
spring
+mybatis:轻量级敏捷开发框架
swargger:快速构建RestFul接口测试页面
shiro
:Apache开源权限
管理
框架,包括登录验证,授权,加密,
会话
管理
redis
:Nosql数据库,搭配
shiro
的
会话
管理
功能将session存入
redis
中,
实现
tomcat多
服务器
集群
的session共享
nginx:反向代理
服务器
,用来调度多台tomcat
h2:内存数据库,用于测试
开发环境 ==== jdk1.8+mysql5.7.22+tomcat8.5.32+IDEA
项目部署 ==== 第一次部署项目
1.修改ssm-rs\resources目录下db.properties的数据库账号密码信息
2.启动
redis
服务端,修改ssm-rs\resources\
spring
-config目录下
spring
-
shiro
.xml中
redis
的连接信息,没设置密码的话auth留空
2.创建数据库train_db并执行根目录下的train_db.sql数据库脚本
3.进入到ssm-build目录下,执行clean install -Dmaven.test.skip=true,对整个项目进行构建
4.启动ssm-rs项目,浏览器访问http://localhost/ssm-rs/swagger-ui.html
项目模块 ==== ssm-build
项目聚合模块,可以进入该项目目录,对整个项目进行构建。
mvn clean install -Dmaven.test.skip=true
ssm-parent
父模块,其他模块会继承该模块,引入公共的依赖
ssm-model
模型层模块,提供各种POJO。包括与数据库表对应的模型、传输模型等。提供给service层(ssm-cs)、controller层(ssm-rs)。
ssm-commons
包含各种工具类
ssm-cs
service层和dao层,提供具体的业务逻辑和数据库访问,需要依赖ssm-model模块,并提供出来给ssm-rs模块调用
ssm-rs
controller层,提供RESTFul接口。
基于ssm+
shiro
+
redis
+nginx tomcat
服务器
集群
管理
项目.zip
基于SSM开发的完整项目算法源码,可用于毕业设计、课程设计、练手学习等
高性能WEB开发
25,980
社区成员
4,366
社区内容
发帖
与我相关
我的任务
高性能WEB开发
高性能WEB开发
复制链接
扫一扫
分享
社区描述
高性能WEB开发
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章