Skip to main content
Managing user’s data with
Spring Session
David  Gómez  G.  
@dgomezg
@dgomezg
Agenda
• Session  Data:  State  of  the  art  
• Spring-­‐Session:  Motivations  &  Goals  
• Out  of  the  box  integration  with  Redis  
• Use  Cases  
• Change  persistent  store  
• Multiple  user  login  handling  
• Adding  session  to  RESTful  APIs
@dgomezg
Session  Data:  State  of  the  art.
• Sometimes  you  need/want  to  keep  data  from  
the  user
@dgomezg
Session  Data:  State  of  the  art.
• HttpSession  as  data  container  
• Retrieved  from  the  HttpServletRequest  
• Implementation  dependent  on  servlet  
container  
• Persistency  configurable  on  servlet  
container
@dgomezg
Scalability:  Clustering,  PASS  and    
Cloud
@dgomezg
Session  Data:  Caveats
• Data  should  be  Serializable  
• Servlet  Container  specific  
• Implementation  
• Persistent  storage  configuration.
@dgomezg
Spring  session  motivation
• Provide  a  mechanism  to  store  &  configure  
session  data  handling
@dgomezg
Spring  Session  Goals
• Provide  a  mechanism  to  store  &  configure  
session  data  handling  
• Platform  independent  
• Transparent  to  standard  HttpSession  usage  
• Easily  configurable  
• Easily  extensible  
• New  persistence  mechanisms
@dgomezg
INTRODUCING  
SPRING  SESSION
9
@dgomezg
How  it  works
Session  is  accessed  via  HttpRequest
@RequestMapping("/user/session")

public String addToSession(HttpServletRequest request,

@RequestParam("attr") String attribute,

@RequestParam("val") String value) {

HttpSession session = request.getSession();

session.setAttribute(attribute, value);

return "redirect:/";

}
The  Goal:  intercept  the  Session  access  to  
  replace  the  Session  creation  by  a  richer  implementation
@dgomezg
Architecture
SessionRepositoryFilter
Other  filters
DispatcherServlet
HttpRequestWrapper
HttpSessionWrapper
Transparently  replaces    
HttpRequest  &  HttpSession
@dgomezg
SessionRepositoryRequestWrapper
Overrides  methods  that  return  an  HttpSession  
•Encapsulates  creation  of  specific  HttpSession  
•Handles  HttpSession  persistence  (if  any)
private final class SessionRepositoryRequestWrapper
extends HttpServletRequestWrapper {
@Override

public HttpSession getSession(boolean create) {/* Impl omitted */}



@Override

public HttpSession getSession() {/* Impl omitted */}

}
@dgomezg
HttpSessionWrapper
Specific  HttpSession  implementation    
•Transparent  interface  for  the  Application  
•Independent  from  Servlet  Container  
•Spring-­‐Session  and  Spring-­‐Repository  aware
private final class HttpSessionWrapper implements HttpSession {

}
@dgomezg
SessionRepositoryFilter
Bootstraps  Spring  Session  architecture  
Should  be  placed  first  in  the  Filter  Chain  
Bean  name  is  mandatory:  
• springSessionRepositoryFilter
<filter>

<filter-name>springSessionRepositoryFilter</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

</filter>

<filter-mapping>

<filter-name>springSessionRepositoryFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

@dgomezg
SessionRepositoryFilter
Bootstraps  Spring  Session  architecture  
Servlet  3.0:  
  Use  AbstractHttpSessionApplicationInitializer  
public class Initializer

extends AbstractHttpSessionApplicationInitializer {



public Initializer() {

super(Config.class);

}

}
@dgomezg
The  Big  Picture
@dgomezg
USING  SPRING  SESSION  IN  YOUR  
APPLICATION
17
@dgomezg
Components  needed
• SpringSessionFilter  (already  implemented)  
• A  SessionRepository  implementation  
• A  redis  backed  implementation  out-­‐of-­‐the-­‐
box  
• A  persistence  service  (optional)  
• (i.e)  an  external  redis  service
@dgomezg
Step  1:  Setup  dependencies
<dependencies>
<dependency>
<groupId>org.springframework.session</groupId>

<artifactId>spring-session</artifactId>

<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>

<artifactId>spring-session-data-redis</artifactId>

<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>

<artifactId>spring-web</artifactId>

<version>4.1.6.RELEASE</version>
</dependency>
</dependencies>
@dgomezg
Step  2:  Import  Redis  Configuration
<context:annotation-config/>

<bean
class="org.springframework.session.data.redis.config.annotation.web.ht
tp.RedisHttpSessionConfiguration"/>
RedisHttpSessionConfiguration  configures:  
• SessionRepositoryFilter  
• A  SessionRepository  that  persists  to  redis  
• needs  a  RedisConnectionFactory
spring/session.xml
@dgomezg
Step  2:  Import  Redis  Configuration
@EnableRedisHttpSession
//@Import(RedisHttpSessionConfiguration.class)
public class Config {

}
RedisHttpSessionConfiguration  configures:  
• SessionRepositoryFilter  
• A  SessionRepository  that  persists  to  redis  
• needs  a  RedisConnectionFactory
@dgomezg
Step  3:  RedisConnectionFactory
<bean id="connectionFactory"

class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"

p:hostName="${redis.host}" p:port="${redis.port}"
p:password="${redis.pass}"/>



<context:property-placeholder location="classpath:redis.properties"/>
Using  Jedis  client  
• Defined  in  spring-­‐data-­‐redis.jar  
Configures  the  external  connection  to  Redis  server  
spring/redis.xml
@dgomezg
Step  3:  RedisConnectionFactory
@Bean

public JedisConnectionFactory connectionFactory(
@Value("${spring.redis.host") String host,

@Value(“${spring.redis.port}”) int port,

@Value("${spring.redis.pass}") String pass) {

JedisConnectionFactory connection = new JedisConnectionFactory();

connection.setHostName(host);

connection.setPort(port);

connection.setPassword(pass);

return connection;

}
Using  Jedis  client  
• Defined  in  spring-­‐data-­‐redis.jar  
Configures  the  external  connection  to  Redis  server  
@dgomezg
Step  3b:  RedisConnectionFactory
@EnableEmbeddedRedis // @Import(EmbeddedRedisConfiguration.class)

@EnableRedisHttpSession 

public class Config {





@Bean

public JedisConnectionFactory connectionFactory(
@RedisServerPort int port) {

JedisConnectionFactory connection =
new JedisConnectionFactory(); 

connection.setPort(port);

return connection;

}

}
An  embedded  Redis  Configuration  is  available  in  
spring-­‐session-­‐samples  project
@dgomezg
Step  4:  Session  usage
@Controller

public class SessionDataController {



@RequestMapping("/user/session")

public String addToSession(HttpServletRequest request,

@RequestParam("attr") String attribute,

@RequestParam("val") String value) {

HttpSession session = request.getSession();

session.setAttribute(attribute, value);

return "redirect:/";

}

}

Use  your  HttpSession  as  usual    
(through  HttpServletRequest)
@dgomezg
Step  5:  Bootstrap  SpringSession
public class Initializer

extends AbstractHttpSessionApplicationInitializer {



public Initializer() {

super(Config.class);

}

}
Define  a  DelegatingFilterProxy  with  specific  name  
springSessionRepositoryFilter
@dgomezg
Step  6:  Deploy  and  test
$ curl https://localhost:8080/user/session?attr=username&val=dgomezg
$
$ ./redis-cli -p 6379
127.0.0.1:6379> keys *
1) "spring:session:expirations:1430159640000"
2) "spring:session:sessions:c7f8d8e3-df49-43d1-866a-ca442c99df91"
127.0.0.1:6379>
@dgomezg
Step  6:  Deploy  and  test
$ curl https://localhost:8080/user/session?attr=username&val=dgomezg
$
$ ./redis-cli -p 6379
127.0.0.1:6379> keys *
1) "spring:session:expirations:1430159640000"
2) "spring:session:sessions:c7f8d8e3-df49-43d1-866a-ca442c99df91"
127.0.0.1:6379>
127.0.0.1:6379> hgetall spring:session:sessions:c7f8d8e3-df49-43d1-866a-ca442c99df91
1) "lastAccessedTime"
2) "xacxedx00x05srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexr
x00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01Lxfcx0cx84?"
3) "maxInactiveInterval"
4) "xacxedx00x05srx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01I
x00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00ab"
5) "creationTime"
6) "xacxedx00x05srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexr
x00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01Lxfcx0ckx01"
7) "sessionAttr:username"
8) "xacxedx00x05tx00adgomezg"
127.0.0.1:6379>
@dgomezg
FURTHER  CUSTOMIZATION
29
@dgomezg
Further  customization
• Out  of  the  box  impl.  implies:  
• MaxInactiveInterval  =  30  min    
• Session  id  exchanged  through  cookies  
(SessionStrategy)  
• SessionStore:  
RedisOperationsSessionRepository  
• RedisSerialization  
• All  defined  in  RedisHttpSessionConfiguration
@dgomezg
Default  inactive  time
• Configurable  as  property  in  
RedisHttpSessionConfiguration
<context:annotation-config/>

<bean
class=“org.springframework.session.data.redis.config.annotation.web.ht
tp.RedisHttpSessionConfiguration"
p:maxInactiveIntervalInSeconds="3600"/>
spring/session.xml
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600) 

public class Config {

}
@dgomezg
Session  Strategy
Configures  the  policy  to  exchange  the  session  Id.  
Two  implementations:  
•CookieSessionStrategy  (default)  
•HeaderHttpSessionStrategy  
<context:annotation-config/>

<bean
class=“org.springframework.session.data.redis.config.annotation.web.ht
tp.RedisHttpSessionConfiguration"
p:maxInactiveIntervalInSeconds="3600"/>
spring/session.xml
@dgomezg
CookieSessionStrategy
Default  strategy  on  RedisHttpSessionConfiguration  
Sets  a  Cookie  with  the  session  ID.
@dgomezg
CookieSessionStrategy
Can  be  customised  to  change  cookie  name
<context:annotation-config/>
<bean id="httpSessionStrategy"

class="org.springframework.session.web.http.CookieHttpSessionStrategy"

p:cookieName="UserSessionID"/>



<bean class=“o.s.s.d.r.c.annotation.web.http.RedisHttpSessionConfiguration"
p:httpSessionStrategy-ref=“httpSessionStrategy”/>
spring/session.xml
@dgomezg
HeaderHttpSessionStrategy
Session  id  is  specified  on  request  headers  
• x-­‐auth-­‐token  by  default  
• header  name  can  be  modified
<context:annotation-config/>
<bean id="httpSessionStrategy"

class="org.springframework.session.web.http.HeaderHttpSessionStrategy"

p:headerName=“x-auth-token“/>



<bean class=“o.s.s.d.r.c.annotation.web.http.RedisHttpSessionConfiguration"
p:httpSessionStrategy-ref=“httpSessionStrategy”/>
spring/session.xml
@dgomezg
Your  own  Strategy
Other  strategies  can  be  implemented  &  plugged  
Implement  HttpSessionStrategy
public interface HttpSessionStrategy {



String getRequestedSessionId(HttpServletRequest request);



void onNewSession(Session session,
HttpServletRequest request,
HttpServletResponse response);



void onInvalidateSession(HttpServletRequest request,
HttpServletResponse response);

}

@dgomezg
USE  CASE  1  
CHANGE  PERSISTENCE  STORE
37
@dgomezg
Customize  SessionStorage
Different  storage  options  could  be  implemented.  
1)  Implement  a  SessionRepository
public interface SessionRepository<S extends Session> {



S createSession();



void save(S session);



S getSession(String id);



void delete(String id);

}
@dgomezg
Customize  SessionStorage
Different  storage  options  could  be  implemented.  
2)  Inject  to  SessionRepositoryFilter  constructor
public class SessionRepositoryFilter<S extends ExpiringSession>
extends OncePerRequestFilter {

/* … */


public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {

if(sessionRepository == null) {

throw new IllegalArgumentException("SessionRepository cannot be null");

}

this.sessionRepository = sessionRepository;

}

}
@dgomezg
USE  CASE  2  
MULTIPLE  USER  SESSIONS
40
@dgomezg
Multiple  Session  Handling
Session  id  is  :  
1)  exchanged  with  the  client  via  CookieSessionStrategy  
2)  which  is  a  MultipleSessionStrategy
@dgomezg
Multiple  Session  handling
Session  id  is  :  
1)  exchanged  with  the  client  via  CookieSessionStrategy  
2)  which  is  a  MultipleSessionStrategy  
3)  so,  different  session  IDs  are  kept.
@dgomezg
Multiple  Session  handling
Session  id  is  :  
1)  exchanged  with  the  client  via  CookieSessionStrategy  
2)  which  is  a  MultipleSessionStrategy  
3)  so,  different  session  IDs  are  kept.  
4)  all  we  have  to  do  is  specify/select  the  right  one.
@dgomezg
Session  selection
Specific  Session  selected  by  parameter  ?_s=#alias  
http://localhost:8080/?_s=0  
@dgomezg
New  Session  
if  index  is  found  in  array,  session  id  is  used  
otherwise,  new  session  is  created
<a id="addAccount" href=“http://localhost:8080/?_s=17“>
Add Account
</a>
@dgomezg
Compose  new  Session  URL  
We  can  create  the  new  Session  through  the  
HttpSessionManager
<a id=“addAccount" href=“${addAccountUrl}”/>
Add Account
</a>
HttpSessionManager sessionManager =
(HttpSessionManager)
httpRequest.getAttribute(HttpSessionManager.class.getName());
String addAlias = sessionManager.getNewSessionAlias(httpRequest);
httpRequest.setAttribute(“addAccountUrl",
sessionManager.encodeURL(contextPath, addAlias));
@dgomezg
Using  session  index  in  URLs
HttpServletResponseWrapper  automatically  
encodes  the  session  id  in  URL.
class CookieSessionStrategy.MultiSessionHttpServletResponse
extends HttpServletResponseWrapper {
@Override

public String encodeURL(String url) {

url = super.encodeURL(url);



String alias = getCurrentSessionAlias(request);

return
CookieHttpSessionStrategy.this.encodeURL(url, alias);

}

}

@dgomezg
USE  CASE  3  
RESTORING  STATE  TO  RESTFUL  APIS
48
@dgomezg
State  in  RESTful  APIs
We  could  add  State  to  REST  endpoints:  
•  Persisted  on  external  persistent  service  (redis)  
•  Restored  into  the  HttpSession  by  the  filter  
•  Used  trasparently  
@dgomezg
HeaderHttpSessionStrategy
Uses  an  specific  header  in  Response  to  return  
session  ID
@Bean

public HttpSessionStrategy httpSessionStrategy() {

return new HeaderHttpSessionStrategy();

}
@dgomezg
HeaderHttpSessionStrategy
Uses  an  specific  header  in  Response  to  return  session  
ID  
By  default  x-­‐auth-­‐token
@Bean

public HttpSessionStrategy httpSessionStrategy() {

return new HeaderHttpSessionStrategy();

}
@dgomezg
HeaderHttpSessionStrategy
Use  an  HeaderHttpSessionStrategy
@Bean

public HttpSessionStrategy httpSessionStrategy() {

return new HeaderHttpSessionStrategy();

}
@dgomezg
HeaderHttpSessionStrategy
Session  header  name  can  be  customised
@Bean

public HttpSessionStrategy httpSessionStrategy() {

HeaderHttpSessionStrategy sessionStrategy =
new HeaderHttpSessionStrategy();

sessionStrategy.setHeaderName("x-custom-session-id");

return sessionStrategy;

}

@dgomezg
CONCLUSIONS
54
@dgomezg
Conclusions
•HttpSession  not  container  dependant  
•Implementation  
•Configuration  
•Persistent  store  easily  configurable  
•Transparent  for  the  developer    
•SpringSessionFilter,    
•HttpServletRequest/HttpSession  Wrappers
@dgomezg
THANKS!
56
Reach  me  on
dgomezg@autentia.com
@dgomezg
Resources
Spring  guides Spring  samples  repository