现在遇到一个需求就是要求完成简单的单点登录,通过在一个tomcat实例中放置两个webapps应用ROOT应用和CEO应用来完成在ROOT应用登录后,在CEO可以直接使用,而未在ROOT应用登录时,不可以进去CEO应用。

实际上问题就是session如何在两个webapp中实现共享,通过上网搜索发现一个方法

方法1ServletContext

server.xml文件修改如下:

<Host name="localhost"  appBase="webapps"unpackWARs="true" autoDeploy="true">
//WebappA为项目名,crossContext="true"
<Context path="/WebappA" debug="9" reloadable="true" crossContext="true"/>
<Context path="/WebappB" debug="9" reloadable="true" crossContext="true"/>
</Host>

crossContext属性的意思是:如果设置为true,你可以通过ServletContext.getContext() 调用另外一个WEB应用程序,获得ServletContext 然后再调用其getAttribute() 得到你要的对象。

Java代码如下:

WebappA:

HttpSession session = request.getSession();
session.setAttribute("userId", "test");
ServletContext ContextA =session .getServletContext();
ContextA.setAttribute("session", session );

WebappB:

HttpSession sessionB = request.getSession();
ServletContext ContextB = sessionB.getServletContext();
ServletContext ContextA= ContextB.getContext("/WebappA");// 这里面传递的是 WebappA的虚拟路径
HttpSession sessionA =(HttpSession)ContextA.getAttribute("session");
System.out.println("userId: "+sessionA.getAttribute("userId"));

初看这个方法,好像是完成我们的目标,可是在我实际应用时发现一个问题,就是当user1在登录前不可以进入CEO应用,在user1登录后才可以进入CEO应用,但是当user1退出之后,未登录的用户依然可以进入CEO应用。

后来仔细看了一下网上提供的方法,它只是在webappA的ServletContext存储了一个session值,然后传递给webAPPB,但是也仅仅只能传递一个session值,如果有两个用户的时候就会出现session覆盖。

于是探究其他解决方法。

方法2sessionCookiePath

在tomcat conf/context.html中有如下配置

  • sessionCookieName

    The name to be used for all session cookies created for this context. If set, this overrides any name set by the web application. If not set, the value specified by the web application, if any, will be used, or the name JSESSIONID if the web application does not explicitly set one.
  • sessionCookiePath

    The path to be used for all session cookies created for this context. If set, this overrides any path set by the web application. If not set, the value specified by the web application will be used, or the context path used if the web application does not explicitly set one. To configure all web application to use an empty path (this can be useful for portlet specification implementations) set this attribute to / in the global CATALINA_BASE/conf/context.xml file.

    Note: Once one web application using sessionCookiePath="/" obtains a session, all subsequent sessions for any other web application in the same host also configured with sessionCookiePath="/" will always use the same session ID. This holds even if the session is invalidated and a new one created. This makes session fixation protection more difficult and requires custom, Tomcat specific code to change the session ID shared by the multiple applications.

也就是说我们可以通过sessionCookiePath属性使得一个tomcat实例下所有的webapps都共享一个session,通过sessionCookieName来指定sessionCookieName名字。

于是我就在tomcat conf/context.html中配置如下:

<Context sessionCookiePath="/" sessionCookieName="SESSIONID" >
</Context>

然后在进行测试,发现在ROOT应用和CEO应用中确实sessionCookie是一样的。可是当我在ROOT中进行 session.setAttribute();时,CEO应用不能从session中取得值,为null,也就是说,对CEO应用而言,ROOT应用在session所储存的值是不可见的。然后在CEO session中进行session.setAttribute();,ROOT应用总同样无法取得CEO存储在session中的数据,猜想可能是不同的webapps并不会共享相同的session内存,每一个webapps维护自己session HashTable,后来了解到 session管理器是和context容器关联的,也就说每个web应用都会有一个session管理器,所以CEO应用当然无法从ROOT应用存储的session中取值。

方法3redis session 共享

以前曾经了解过Nginx+tomcat+redis做负载均衡的内容,知道可以把session数据存储到redis中,然后tomcat再去redis取值。

而这次的tomcat中session在两个webapp中实现共享其实也可以通过这个方法进行处理。

在tomcat conf/context.html中配置如下:

<Context sessionCookiePath="/" sessionCookieName="SESSIONID" >
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="172.22.4.16"
port="6379"
database="0"
maxInactiveInterval="60" />
</Context>

然后即可实现tomcat中session在两个webapp中实现共享。

jar包和windows redis安装包

http://pan.baidu.com/s/1eSITNnc

session过期策略

tomcat-session怎么实现的过期策略?

首先如果没有使用redis做session缓存,tomcat服务器在启动的时候初始化了一个守护线程,定期6*10秒去检查有没有Session过期.过期则清除。而使用的tomcat-session-redis做缓存,那么session过期之后就由redis进行删除,redis通过惰性删除和定期删除来删除过期的sessionID值。

当然sessionID还存在于客户端,那么客户端的sessionID清理过程是什么?

经过测试是当tomcat删除sessionID值之后,tomcat会重新生成一个sessionID值返回给客户端。

总结:

其实我这个功能就是单点登录,也就是说在A应用登录的情况下可以访问B应用,但是即使设置了sessionCookiePath,session的Attribute并没有共享,于是想到了先把session序列化到redis中,然后取出来判断,这样就可以实现单点登录。核心是session在这两个应用中必须是一样的,通过设置sessionCookiePath

注意:

  1. 当你使用自己的对象执行session.setAttribute();时,必须实现Serializable接口,不然无法进行序列化。
  2. maxInactiveInterval 不起作用

    tomcat日志描述:

    警告: Manager.setMaxInactiveInterval() is deprecated and calls to this method are ignored. Session timeouts should be configured in web.xml or via Context.setSessionTimeout(int timeoutInMinutes).

    信息: Will expire sessions after 120 seconds(默认是30分钟)

    只能通过在ROOT下的web.xml或者全局的web.xml(CEO中的session-config无法生效)中配置才可生效。
    <!--设置session过期时间-->
    <session-config>
    <session-timeout>20</session-timeout>
    </session-config>

    配置成功后tomcat日志:

    信息: Will expire sessions after 120 seconds

  3. 在context中配置host为静态ip 172.22.4.16报错如下:

    ,Google发现原来redis和mysql一样都是已经默认绑定了localhost,只允许本机访问,于是更改redis.windows-service.conf如下
    bind 127.0.0.1 172.22.4.16

    之后就可以使用静态ip 172.22.4.16进行访问。

  4. msi应用的安装,修复和卸载都是通过点击msi文件。
  5. 还有一个共享session的方案是spring-session。 spring-session中通过自己生成session并且存储到redis中,还是需要设置sessionCookiePath="/"(在一个tomcat两个应用需要单点登录的情况),其他session共享方案(在多个tomcat中实现单点登录可以参考 spring session无法实现共享(多web应用)),但是spring-session不是服务器级别的,而是web 应用级别的,不受服务器如tomcat,jetty,jboss的限制。

参考文档

  1. http://tomcat.apache.org/tomcat-7.0-doc/config/context.html
  2. 搭建Tomcat集群&通过Redis缓存共享session的一种流行方案
  3. Tomcat的Session过期处理策略
  4. Tomcat中session的管理机制

tomcat中session在两个webapp中实现共享的更多相关文章

  1. 使用Eclipse在Excel中找出两张表中相同证件号而姓名或工号却出现不同的的项

    1:首先把Excel中的文本复制到txt中,复制如下: A表: 证件号                           工号  姓名 310110xxxx220130004 101 傅家宜3101 ...

  2. ASP.NET中Session的sessionState 4种mode模式

    1. sessionState的4种mode模式 在ASP.NET中Session的sessionState的4中mode模式:Off.InProc.StateServer及SqlServer. 2. ...

  3. hibernate中session

    hibernate中的session是一级缓存,可以理解为进程级的缓存.在进程运行期间一直存在. session可以理解为一个可以操作数据库的对象 具体如何操作数据库? session中有方法, 如果 ...

  4. 如何严格设置php中session过期时间

    如何严格限制session在30分钟后过期! 1.设置客户端cookie的lifetime为30分钟: 2.设置session的最大存活周期也为30分钟: 3.为每个session值加入时间戳,然后在 ...

  5. 第六篇 flask中session

    Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪 Flask 中 session 的使用 1. Flask 中 session 是 ...

  6. 在Django中Session的那点事!

    1.session是什么 首先引入度娘的解释:Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 We ...

  7. 如何严格设置php中session过期时间 (转)

    如何严格限制session在30分钟后过期!1.设置客户端cookie的lifetime为30分钟:2.设置session的最大存活周期也为30分钟:3.为每个session值加入时间戳,然后在程序调 ...

  8. (转)tomcat架构&session共享

    (二期)16.tomcat的整体架构与session共享方案 [课程16]tomcat...共享.xmind47.6KB [课程16]tomcat...流程.xmind0.6MB [课程16]tomc ...

  9. 刚刚大学毕业,自己搭网站遇到的问题 一:tomcat中同时部署两个项目的问题

    最近直接把两个项目打成war包在tomcat下发布,出现了很多莫名奇妙的问题,就是不能发布成功,只能有一个项目能成功,在网上查了很多方法,以为是两个项目中jar包出现冲突,也按照网上的方法把两个项目中 ...

随机推荐

  1. java初学

    1.Scanner类 1)使用 a.导入Scanner类 improt java.util.Scanner; b.创建Scanner对象 Scanner input = new Scanner(Sys ...

  2. IDEA的破解安装以及汉化

    IDEA是一款比eclipse用起来更好用的一款代码编辑器,本人之前也是一直在用eclipse来写代码,后来发现了IDEA用起来会更顺手,所以又转用IDEA了,今天给大家分享一下IDEA的下载安装破解 ...

  3. 微信小程序模板消息详解

    先放代码 wxml: <form name='pushMsgFm' report-submit bindsubmit='orderSign'> <view> 单号: 0< ...

  4. solr服务的搭建(以solr4.1实现)

    1.准备工作:一个干净的Tomcat,solr-4.10.3. 2.新建一个文件夹我这里命名为solr,将Tomcat和solr-4.10.3放进去.新建一个solrhome的文件夹,里面放的是sol ...

  5. 使用Git将本地项目或代码上传到GitHub上

    1.要托管到github,那你就应该要有一个属于你自己的github帐号,所以你应该先到github.com注册.打开浏览器在地址栏输入地址:github.com 填写用户名.邮箱.密码,点击Sign ...

  6. API接口签名验证2

    http://www.jianshu.com/p/d47da77b6419 系统从外部获取数据时,通常采用API接口调用的方式来实现.请求方和�接口提供方之间的通信过程,有这几个问题需要考虑: 1.请 ...

  7. php匹配图片、视频文件、音乐文件的正则表达式

    $pattern_video = "/(src)=(\\\?)([\"|']?)([^ \"'>]+\.(swf|flv|mp4|rmvb|avi|mpeg|ra| ...

  8. CSS容器属性

    最近一直想美化博客的文字效果和增加文章末尾的转发提示,所以这两天抽空研究了一下CSS,前两篇可以翻我的博客,今天写的这篇是介绍增加文章末尾的转发提示,效果如文章末尾所示,好了,CSS很简单,我就不介绍 ...

  9. Java接口和抽象类的理解

    接口和抽象类的相同之处就是 都会有抽象方法 抽象方法就是一个没有方法体 等待继承的子类完成的方法 然而接口比较严格 它的方法必须是抽象方法且是公开的 抽象类 可以有自己的属性 和 实体方法 首相用面向 ...

  10. 商品鼠标移过去hover效果---图片放大1.1倍

    .home-standard-layout .middle-goods-list ul li:hover{ box-shadow: 0 0 10px gray;} .home-standard-lay ...