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

Managing user's data with Spring Session

  • 1.
    Managing user’s datawith Spring Session David  Gómez  G.   @dgomezg
  • 2.
    @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
  • 3.
    @dgomezg Session  Data:  State of  the  art. • Sometimes  you  need/want  to  keep  data  from   the  user
  • 4.
    @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
  • 5.
  • 6.
    @dgomezg Session  Data:  Caveats •Data  should  be  Serializable   • Servlet  Container  specific   • Implementation   • Persistent  storage  configuration.
  • 7.
    @dgomezg Spring  session  motivation •Provide  a  mechanism  to  store  &  configure   session  data  handling
  • 8.
    @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
  • 9.
  • 10.
    @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
  • 11.
  • 12.
    @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 */}
 }
  • 13.
    @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 {
 }
  • 14.
    @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>

  • 15.
    @dgomezg SessionRepositoryFilter Bootstraps  Spring  Session architecture   Servlet  3.0:    Use  AbstractHttpSessionApplicationInitializer   public class Initializer
 extends AbstractHttpSessionApplicationInitializer {
 
 public Initializer() {
 super(Config.class);
 }
 }
  • 16.
  • 17.
    @dgomezg USING  SPRING  SESSION IN  YOUR   APPLICATION 17
  • 18.
    @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
  • 19.
    @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>
  • 20.
    @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
  • 21.
    @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
  • 22.
    @dgomezg Step  3:  RedisConnectionFactory <beanid="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
  • 23.
    @dgomezg Step  3:  RedisConnectionFactory @Bean
 publicJedisConnectionFactory 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  
  • 24.
    @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
  • 25.
    @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)
  • 26.
    @dgomezg Step  5:  Bootstrap SpringSession public class Initializer
 extends AbstractHttpSessionApplicationInitializer {
 
 public Initializer() {
 super(Config.class);
 }
 } Define  a  DelegatingFilterProxy  with  specific  name   springSessionRepositoryFilter
  • 27.
    @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>
  • 28.
    @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>
  • 29.
  • 30.
    @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
  • 31.
    @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 {
 }
  • 32.
    @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
  • 33.
    @dgomezg CookieSessionStrategy Default  strategy  on RedisHttpSessionConfiguration   Sets  a  Cookie  with  the  session  ID.
  • 34.
    @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
  • 35.
    @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
  • 36.
    @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);
 }

  • 37.
    @dgomezg USE  CASE  1  CHANGE  PERSISTENCE  STORE 37
  • 38.
    @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);
 }
  • 39.
    @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;
 }
 }
  • 40.
    @dgomezg USE  CASE  2  MULTIPLE  USER  SESSIONS 40
  • 41.
    @dgomezg Multiple  Session  Handling Session id  is  :   1)  exchanged  with  the  client  via  CookieSessionStrategy   2)  which  is  a  MultipleSessionStrategy
  • 42.
    @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.
  • 43.
    @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.
  • 44.
    @dgomezg Session  selection Specific  Session selected  by  parameter  ?_s=#alias   http://localhost:8080/?_s=0  
  • 45.
    @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>
  • 46.
    @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));
  • 47.
    @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);
 }
 }

  • 48.
    @dgomezg USE  CASE  3  RESTORING  STATE  TO  RESTFUL  APIS 48
  • 49.
    @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  
  • 50.
    @dgomezg HeaderHttpSessionStrategy Uses  an  specific header  in  Response  to  return   session  ID @Bean
 public HttpSessionStrategy httpSessionStrategy() {
 return new HeaderHttpSessionStrategy();
 }
  • 51.
    @dgomezg HeaderHttpSessionStrategy Uses  an  specific header  in  Response  to  return  session   ID   By  default  x-­‐auth-­‐token @Bean
 public HttpSessionStrategy httpSessionStrategy() {
 return new HeaderHttpSessionStrategy();
 }
  • 52.
    @dgomezg HeaderHttpSessionStrategy Use  an  HeaderHttpSessionStrategy @Bean
 publicHttpSessionStrategy httpSessionStrategy() {
 return new HeaderHttpSessionStrategy();
 }
  • 53.
    @dgomezg HeaderHttpSessionStrategy Session  header  name can  be  customised @Bean
 public HttpSessionStrategy httpSessionStrategy() {
 HeaderHttpSessionStrategy sessionStrategy = new HeaderHttpSessionStrategy();
 sessionStrategy.setHeaderName("x-custom-session-id");
 return sessionStrategy;
 }

  • 54.
  • 55.
    @dgomezg Conclusions •HttpSession  not  container dependant   •Implementation   •Configuration   •Persistent  store  easily  configurable   •Transparent  for  the  developer     •SpringSessionFilter,     •HttpServletRequest/HttpSession  Wrappers
  • 56.