One of the new features in the Apache Shiro 1.3 release is the support for a Hazelcast Cache Manager. In this post, we will walk through updating an existing application and add clustered session support via Hazelcast, all with only a few configuration changes.
Download the Sample Web App
First, download the simple web application:
1 2 |
git clone https://github.com/stormpath/stormpath-shiro-hazelcast-tutorial.git /path/to/shiro-hazelcast-tutorial |
Next we need to run two instances of our application, in order to see the session interaction between them.
You will need two terminal/console windows, both starting in the same directory /path/to/shiro-hazelcast-tutorial
.
In one of the terminals, run:
1 2 |
mvn jetty:run -Djetty.port=9091 |
And in the second terminal, on a different port:
1 2 |
mvn jetty:run -Djetty.port=9092 |
Now open a browser, log in, and see what happens.
Open http://localhost:9091, and login as root/secret. Now, in the same browser, with a new tab or window: http://localhost:9092, and login as root again.
Great! Now you have logged into both applications, but, there is a problem. Go back to the first browser window, and reload the page. What? The user is logged out? Now try the same thing in the other browser window. Shoot! Same thing!
This is expected, the browser session is being tracked by a cookie (and not restricted by port), the two application’s sessions are stepping on each other, and the users are both logged out. In a real world deployment both of servers would be behind a load balancer, but you would get similar results.
Stop the servers that are running (control-C), so we can fix this problem.
Hazelcast to the Rescue
To add Hazelcast to our application, there are two things we need to do: add the dependency to the Maven pom file, and configure our shiro.ini
to use the new Cache Manager.
Open up the pom.xml
file and near the bottom of the file, just before the closing </dependencies>
tag, add:
1 2 3 4 5 6 |
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-hazelcast</artifactId> <version>1.3.0</version> </dependency> |
Next edit the Shiro configuration, open src/main/webapp/WEB-INF/shiro.ini
, in the [main]
section add the following configuration:
1 2 3 4 5 6 7 8 9 10 11 12 |
# use native session management so we can configure our own session clustering: sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager sessionManager.sessionDAO = $sessionDAO # We have configured Hazelcast to enforce a TTL for the activeSessions Map. No need for Shiro to invalidate! sessionManager.sessionValidationSchedulerEnabled = false securityManager.sessionManager = $sessionManager # Configure Hazelcast as our Shiro CacheManager. Adding session capacity is as easy as adding Hazelcast nodes! cacheManager = org.apache.shiro.hazelcast.cache.HazelcastCacheManager securityManager.cacheManager = $cacheManager |
Done! Let’s fire this up and test it.
Start the servers again:
1 2 |
mvn jetty:run -Djetty.port=9091 |
And in the second terminal:
1 2 |
mvn jetty:run -Djetty.port=9092 |
Back in your browser open (or refresh) http://localhost:9091 and login as root. This time, when you open the second browser window to http://localhost:9092, you will already be logged in! The session information has already been synchronized between the two applications.
Advanced Configuration
So far we have just used the default out of the box Hazelcast configuration. All we need to do to change the Hazelcast configuration, is add a hazelcast.xml to the class path.
Download the sample hazelcast.xml to src/main/resources/hazelcast.xml
1 |
curl -o src/main/resources/hazelcast.xml https://raw.githubusercontent.com/stormpath/stormpath-shiro-hazelcast-tutorial/step-3/src/main/resources/hazelcast.xml |
For our purposes we are just going to change the cluster name and ports, take a look the Hazelcast documentation, for more configuration options.
Change the lines:
1 2 3 4 5 |
<group> <name>dev</name> <password>dev-pass</password> </group> |
to:
1 2 3 4 5 |
<group> <name>shiro-example</name> <password>dev-pass</password> </group> |
And to change the starting port range:
1 |
<port auto-increment="true">5701</port> |
to:
1 |
<port auto-increment="true">5801</port> |
Restart your servers again via the mvn jetty:run
commands from above. After starting the second server, you should see log message similar to this in the console:
1 2 3 4 5 6 7 |
INFO: [127.0.0.1]:5802 [shiro-example] Members [2] { Member [127.0.0.1]:5801 Member [127.0.0.1]:5802 this } |
There you have it, session clustering, with minimal configuration changes.