📜 ⬆️ ⬇️

Storing sessions in Redis and sharing them in PHP and Tomcat

Actually the task is very specific, but this work may still be useful to someone. The question of the feasibility of sharing Apache and Tomcat I propose to leave behind the discussion. The task was set at work as a given. It is required to provide storage of sessions in Redis for PHP and Tomcat and so that these sessions were common between them. A long googling did not result. Both for PHP and for Tomcat there are means of storing sessions in Redis, but the storage format is different. All 3 projects found for Tomcat serialize sessions on Redis using a binary format to serialize Java objects. Also PHP and Tomcat have different identifiers for the session cookie (PHPSESSID and JSESSID, respectively).

Actually, these problems I had to solve. If possible, I wanted to do everything in my mind: without inventing my own API for working with sessions; not inventing the own generation function of a unique and random ID for the session (in such things it’s easy to mess up, making the whole project vulnerable); by writing a minimum of code duplicating the functionality already invented by others.
With PHP everything turned out to be extremely simple. There is a wonderful project that, while saving a session, serializes its attributes in JSON. In addition, PHP allows you to change the name of the cookie used on the client using the session-name function. So it turned out that almost nothing happened with PHP.
Tomcat is more complicated. Among the found 3 projects that provide the ability to store sessions in Redis, there was not one able to save the session into anything other than the binary object serialization format in Java, which is somewhat difficult to read using PHP (and even if not, then sure is a bad practice).
However, the Tomcat Redis Session Manager project allows you to use your own object serialization implementations, which allows you to solve the problem of storing a session in Redis in JSON format.
To code

Php

So the session creation code in PHP looks like this:
#  , ,        #  ,     require('redis-session-php/redis-session.php'); #  ,       # Redis.   , . .  tomcat-redis-session-manager # ,      define('REDIS_SESSION_PREFIX', ''); #  Tomcat      ,    PHP session_name('JSESSIONID'); #    RedisSession::start(); 

The script works like this:

As a result, the record with the key - the session id and the session data serialized in JSON will fall into Redis.

Java is a bit more complicated.
Java

First you need to install Redis Session Manager. The installation process is described in detail on the official website of the project. We register in context.xml:
 <Valve className="com.radiadesign.catalina.session.RedisSessionHandlerValve" /> <Manager className="com.radiadesign.catalina.session.RedisSessionManager" serializationStrategyClass="com.radiadesign.catalina.session.JSONSerializer"/> 

Here I do not prescribe the parameters that I have with the default parameters (for example, the server is localhost), besides, the serializationStrategyClass parameter is added, which sets the path to my own implementation of the session serialization class (the code will be lower).
Download tomcat-redis-session-manager-1.2-tomcat-6.jar to your Tomcat's lib folder.
The serialization class looks like this:
 package com.radiadesign.catalina.session; import javax.servlet.http.HttpSession; import java.io.IOException; import java.util.HashMap; import java.util.Enumeration; import java.util.Map; import java.io.ByteArrayOutputStream; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.util.Iterator; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; public class JSONSerializer implements Serializer { private ClassLoader loader; @Override public void setClassLoader(ClassLoader loader) { this.loader = loader; } @Override public byte[] serializeFrom(HttpSession session) throws IOException { // create map to put data here HashMap<String,Object> sessionData = new HashMap<String,Object>(); // put every attribute of session in newly created map for (Enumeration keys = session.getAttributeNames(); keys.hasMoreElements();){ String k = (String) keys.nextElement(); sessionData.put(k, session.getAttribute(k)); } // write it to byte array Gson gson = new Gson(); return gson.toJson(sessionData).getBytes(); } @Override public HttpSession deserializeInto(byte[] data, HttpSession session) throws IOException, ClassNotFoundException { RedisSession redisSession = (RedisSession) session; redisSession.setValid(true); // place data to map Gson gson = new Gson(); Type mapType = new TypeToken<HashMap<String,Object>>(){}.getType(); HashMap<String,Object> sessionData = gson.fromJson(new String(data), mapType); // place attributes to session object for (Map.Entry<String, Object> entry : sessionData.entrySet()) redisSession.setAttribute(entry.getKey(), entry.getValue()); // return filled session*/ return redisSession; } } 

Here, the Json library is used for serialization in JSON, so if you don’t have it, install it.
Compile the class in Jar and put it in the lib folder of your copy of Tomcat. An example of my compilation team:
 javac -cp /usr/share/tomcat6/lib/servlet-api.jar:/usr/share/tomcat6/lib/catalina.jar:/usr/share/tomcat6/lib/tomcat-redis-session-manager-1.2-tomcat-6.jar:/usr/share/tomcat6/lib/gson-2.2.2.jar com/radiadesign/catalina/session/JSONSerializer.java jar cf jsonserializer.0.1.jar com 

Of course, the path to the libraries may differ on your machine. If you’re too lazy to compile it yourself, get a ready-made Jar from my Dropbox .
Everything. After that, you can create sessions in the usual way, everything works completely transparent. If you have completed these steps for Tomcat and are creating sessions in PHP using the code above, then you have common sessions between Tomcat and PHP.
Just in case, I give an example of creating a session in Tomcat:
 import java.io.*; import javax.servlet.http.*; import javax.servlet.*; public class HelloServlet extends HttpServlet { public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { PrintWriter out = res.getWriter(); HttpSession session = req.getSession(); out.println("ID: " + session.getId()); session.setAttribute("Name", "kapitoka"); out.println("Set done"); out.println("Get result: " + session.getAttribute("Name")); out.close(); } } 

As you can see, no specific actions are required, a completely ordinary session creation code.
Result of the Java example:

')

Source: https://habr.com/ru/post/169241/


All Articles