Sharing session data between contexts in Tomcat
I have been looking at solutions for sharing session data between mutliple war files. I came across the following solution http://www.fwd.at/tomcat/sharing-session-data-howto.html
The basic idea of it is that if you have more than one war file, you can set a cookie using the sessionid of the first context that is used.
The cookie can be set using a path that will apply to all contexts/applications.
For example, if I have the following configuration for 3 applications
/myapp/app1
/myapp/app2
/myapp/app3
I can set a cookie as follows
/myapp sessionid.
The sessionid cookie will then be sent to any request with /myapp in the address. This allows the session id to then be used by any of the contexts.
The only problem with this approach is that it was written in 2003 and tested on Tomcat 4.
What are your opinions of this approach? Is there a better way of doing it?
Thanks
Solution 1:
That article is indeed heavily outdated.
On Tomcat 5.5 and 6.0 you can just set emptySessionPath
attribute to true
in the <Connector>
element in /conf/server.xml
.
<Connector ... emptySessionPath="true">
On Tomcat 7.0 this has changed because this is now configureable from the Servlet 3.0 API on. It's then on Tomcat's side configureable by setting sessionCookiePath
to /
in <Context>
element in any responsible context.xml
file.
<Context ... sessionCookiePath="/">
As said, there's a new Servlet 3.0 API which allows you to configure the session cookie through the standard API. You can do it either declaratively by adding the following to the web.xml
:
<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>
or programmatically by SessionCookieConfig
which is available by ServletContext#getSessionCookieConfig()
.
getServletContext().getSessionCookieConfig().setPath("/");
You could do this in ServletContextListener#contextInitialized()
or HttpServlet#init()
.
See also:
- Tomcat 5.5 HTTP connector documentation
- Tomcat 6.0 HTTP connector documentation - mentions potential security hole
- Tomcat 7.0 context documentation
Solution 2:
To my knowledge there is no direct way to do this, you can however use a domain level cookie if these contexts share the same domain.
You can either put the data in the cookie (I don't recommend that).
Or put a secured session Id that you can use to access some form of storage (DB or distributed cache etc) to retrieve the data you need.
Solution 3:
If the amount of data is not astronomical and the data itself isn't changing too rapidly, you might want to consider using JNDI. This solution was designed exactly for what you are looking for.
You can have a look at official documentation or this post to tomcat-user mailing list for references & examples.
Solution 4:
For Tomcat 8 I use the following configuration to share a session across 2 webapps:
conf/context.xml
<Context sessionCookiePath="/">
<Valve className="org.apache.catalina.valves.PersistentValve"/>
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
</Manager>
...
</Context>
I deploy the same simple webapp twice log.war and log2.war:
/log
/log2
I can now log-in to /log
and have the user displayed in /log2
, this does not work with the tomcat default configuration.
The session value is set and read:
HttpSession session=request.getSession();
session.setAttribute("name",name);
HttpSession session=request.getSession(false);
String name=(String)session.getAttribute("name");
I used this project as example: https://www.javatpoint.com/servlet-http-session-login-and-logout-example
Most examples/solutions use a in-memory database which requires more setup work:
- redis
- hazelcast