cas的session存储及实现共享的原理:

cas在HashMapBackedSessionMappingStorage存session所以后面可以根据自己的tic,结合cookie反向生成session放到新的web服务器中

集群思想:cas通过redis覆写可以实现多节点cas的集群(都是用redis存储session,不再使用HashMapBackedSessionMappingStorage这个内部的map存)

cas是开源的登录认证方案,可以实现多个web应用的单点登录。

随着用户量的增加,web应用需要部署多个实例,要实现不同应用、多实例的共享session,需要先了解cas的logout机制。简单的说,web应用在接入cas的时候需要继承cas-client-core,这个模块完成的事情如下:

  • 拦截到web应用的请求,验证登录状态,若未登录则跳转到登录页
  • 登录成功,web应用的tomcat存储session,cas-server保存TGT信息,cas-client-core保存ST和session的对应关系
  • 登出时由cas-server返回ST信息,cas-client-core根据ST删除自己存储在内存的ST和session信息
要实现共享session,就需要解决以下两个问题:
  • tomcat共享session
  • cas-client-core共享ST和session的对应关系

tomcat共享session

tomcat默认的session是存在在内存的,因此要实现共享就需要实现session存储到数据库,考虑到用户操作需要频繁读取session,因此redis很适合用来实现session统一存储。
tomcat-redis-session-manager是开源的tomcat共享session插件,这里需要注意要下载比较新的master版本,我当时是下了稳定版本tomcat-redis-session-manager-1.2-tomcat-7-java-7,结果一直在死循环,阅读源码才修改了其中的bug,后面发现master已经修复bug。
我用的插件版本如下:
  • commons-pool-1.6.jar
  • jedis-2.0.0.jar
  • 修改bug后的tomcat-redis-session-manager-1.2-tomcat-7-java-7.jar
然后按照官网的说明,只需要在tomcat的context.xml简单加上配置就ok

cas-client-core共享ST和session

cas-client-core利用HashMapBackedSessionMappingStorage实现了ST和session的内存存储,因此很简单,我们只需要实现使用redis存储ST和session的缓存,替换该接口即可。
这里在序列化存储的时候碰到头疼的问题,StandardSessionFacade没有实现序列化,如果改动StandardSessionFacade需要重新编译catalina的jar包,比较麻烦所以没有选择该方案。
那怎么办呢?在集成了tomcat-redis-session-manager插件后,tomcat使用的session最终实例其实还是RedisSession,这个必然实现了序列化接口,因此我们只需要存储这个实例即可。问题来了,StandardSessionFacade的变量session为private,真是处处坑。。只能用java反射来获取了。以下是redis保存ST和session的源码:
[java] view plaincopy
  1. @Override
  2. public void addSessionById(String mappingId, HttpSession session) {
  3. String STKey = getKey(mappingId);
  4. StandardSessionFacade standardSessionFacade = (StandardSessionFacade) session;
  5. RedisSession redisSession = null;
  6. try {
  7. redisSession = (RedisSession) getValue(standardSessionFacade, "session");
  8. } catch (IllegalAccessException e) {
  9. e.printStackTrace();
  10. } catch (NoSuchFieldException e) {
  11. e.printStackTrace();
  12. }
  13. if (null == redisSession) {
  14. log.error("get redisSession fail");
  15. return;
  16. }
  17. sessionRedisTemplate.opsForValue().set(STKey, jdkSerializer.serialize(redisSession));
  18. String sessionKey = getKey(session.getId());
  19. stringRedisTemplate.opsForValue().set(sessionKey, STKey);
  20. log.debug("cas-client add session, mappingId:" + mappingId + " sessionId:" + session.getId());
  21. }

保存ok了,接下来看看删除,先来看看SingleSignOutHandler的删除代码:

[java] view plaincopy
  1. public void destroySession(final HttpServletRequest request) {
  2. final String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName);
  3. if (log.isTraceEnabled()) {
  4. log.trace("Logout request:\n" + logoutMessage);
  5. }
  6. final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex");
  7. if (CommonUtils.isNotBlank(token)) {
  8. final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token);
  9. if (session != null) {
  10. String sessionID = session.getId();
  11. if (log.isDebugEnabled()) {
  12. log.debug("Invalidating session [" + sessionID + "] for token [" + token + "]");
  13. }
  14. try {
  15. session.invalidate();
  16. } catch (final IllegalStateException e) {
  17. log.debug("Error invalidating session.", e);
  18. }
  19. }
  20. }
  21. }

invalidate方法会调用StandardSession的expire方法,此处需要利用manager获取上下文信息,但是manager无法存储(测试过使用json序列化或者java 序列化均无法存储manager),因此invalidate不会真正去执行,看了下代码,只是通知一些监听者。so,感觉问题不大,ST和session对应关系信息删除了,接下来就是删除tomcat的session,干脆用了比较trick的方法,在cas-client-core直接删除tomcat的session。附上删除的代码:

[java] view plaincopy
  1. @Override
  2. public HttpSession removeSessionByMappingId(String mappingId) {
  3. String STKey = getKey(mappingId);
  4. log.debug("cas-client remove session, STKey:" + STKey);
  5. RedisSession session = null;
  6. byte[] value = (byte[]) sessionRedisTemplate.opsForValue().get(STKey);
  7. session = (RedisSession) jdkSerializer.deserialize(value);
  8. if (null == session) {
  9. log.error("session is null");
  10. return null;
  11. }
  12. removeBySessionById(session.getId());
  13. sessionRedisTemplate.delete(session.getId());
  14. log.debug("delete session:" + session.getId());
  15. return session;
  16. }
  17. @Override
  18. public void removeBySessionById(String sessionId) {
  19. log.debug("Attempting to remove Session=[" + sessionId + "]");
  20. String sessionKey = getKey(sessionId);
  21. String st = stringRedisTemplate.opsForValue().get(sessionKey);
  22. if (log.isDebugEnabled()) {
  23. if (st != null) {
  24. log.debug("Found mapping for session.  Session Removed.");
  25. } else {
  26. log.debug("No mapping for session found.  Ignoring.");
  27. }
  28. }
  29. stringRedisTemplate.delete(sessionKey);
  30. sessionRedisTemplate.delete(st);
  31. }

实现有点trick,测试暂时没有发现问题,两个实例能够正常登陆、使用和退出。

cas的session存储及实现共享的相关推荐

  1. tomcat实现session集群及tomcat+memcached共享session存储(四)

    接博客nginx或httpd实现负载均衡tomcat(三) tomcat实现会话管理原理及实现: tomcat管理会话使用的专用的会话管理组件,tomcat的会话管理器有4种: 1.标准会话管理器(S ...

  2. 在SpringBoot中使用Spring Session解决分布式会话共享问题

    在SpringBoot中使用Spring Session解决分布式会话共享问题 问题描述: 每次当重启服务器时,都会导致会员平台中已登录的用户掉线.这是因为每个用户的会话信息及状态都是由session ...

  3. C# redis 分布式session存储

    https://github.com/uliian/SessionExtentionStore 一个基于Redis的Session存储扩展方案,解决ASP.NET中Session的局限性和跨应用程序使 ...

  4. 从spring-session存储结构探讨session存储方案的演变

    我们知道Spring Session 主要解决了分布式场景下 Session 的共享问题,本文将从 Spring Session 的源码出发,来讨论一些 Session 设计的细节. 一.Spring ...

  5. 基于shiro实现session持久化和分布式共享

    前言 本文写下session持久化和分布式共享 基于shiro框架对session的管理机制来实现 必要性 一直处于登陆状态:你登陆微信 不可能三天两头就让你重新登陆吧?而是一直处于登陆状态 除非主动 ...

  6. Flask 框架中 上下文基础理念,包括cookie,session存储方法,requset属性,current_app模块和g模块...

    Flask中上下文,分为请求上下文和应用上下文.既状态留存 ,就是把变量存在某一个地方可以调用 请求上下文:实际就是request和session用法理念,既都是可以存储东西. 应用上下文:既变量共享 ...

  7. php session传数组,php session存储数组

    PHP面试干货 1.进程和线程 进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性.进程和线程的区别在于: 简而言之,一个程序至少有一个进程,一个进程至少有一 ...

  8. java session存储6_Session是怎么实现的?存储在哪里?

    目录 前言 文章内容转载或摘录自,如下文章.最后将在文末[博主注]这一部分,指出一些需要注意的地方. 为什么有session? 首先大家知道,http协议是无状态的,即你连续访问某个网页100次和访问 ...

  9. session的复制与共享

    分布式系统开发常见问题 1. session的复制与共享 1.session的复制与共享 在web应用中,为了应对大规模访问,必须实现应用的集群部署.要实现集群部署主要需要实现session共享机制, ...

最新文章

  1. 以Linux系统上的gcc为例,解密C语言编译背后的全过程!
  2. java 虚拟机规范_Java虚拟机规范----Java虚拟机结构
  3. 产业AI实践中,如何有效提升图像识别精度、实现极小目标检测? | 百度AI公开课报名...
  4. Pytorch view()、squeeze()、unsqueeze()、torch.max()
  5. django 1.9 mysql_Python3.5+Django1.9+MySQL57+PyCharm5.0.1配置
  6. 微信支付 php详解,PHP实现微信支付实战案例详解
  7. 学会这个BBC,你的图也可以上新闻啦!
  8. 编程语言对比 导入模块
  9. 海外硕士苏明哲回国后哀叹:我美本英硕,找不到工作很难受
  10. delphi 访问https 接口
  11. leafletjs 热力图_leaflet.js自定义热力图效果实例
  12. python自动化实现QQ自动发说说
  13. while在c语言中的作用,while的用法_C语言中while的用法
  14. 汇新云智慧城市解决方案——以区块链加速智慧城市建设
  15. 基于K-近邻算法的手写数字识别研究
  16. matlab 狼追兔子,数学模型--狼追击兔子的问题.doc
  17. Qt播放视频0x8007000e报错 DirectShowPlayerService::doPlay: Unresolved error code 0x8007000e
  18. java处理excel,将xlsx转xls
  19. android 类似qq空间微博微信九宫格图片
  20. OpenMesh-网格光顺的算法

热门文章

  1. 微信小程序使用onfire.js(事件订阅和分发JavaScript 库)实现跨页面传参,对onfire的全面了解
  2. 在linux下,如何使得某个目录的下的可执行文件,成为系统级的可执行文件
  3. Verycd上.net一些教程,自己留着做备忘..
  4. 计算机组装安装与维护大作业,《电脑组装、使与维护》大作业.doc
  5. STATCOM仿真下载
  6. 索骥馆-科普常识之《漫话哲学》全彩版[PDF]
  7. Mat与BufferedImage相互转换
  8. word快速制作多个单面桌签、号码牌等
  9. 修改GITBASH命令提示符
  10. Unity资产,特殊文件夹以及重要路径