Successfully reported this slideshow.
Your SlideShare is downloading. ×

Managing user's data with Spring Session

Upcoming SlideShare
Spring4 whats up doc?
Spring4 whats up doc?
Loading in …3
×

Check these out next

1 of 56 Ad
1 of 56 Ad
Advertisement

More Related Content

Advertisement

More from David Gómez García (20)

Advertisement

Managing user's data with Spring Session

  1. 1. Managing user’s data with Spring Session David  Gómez  G.   @dgomezg
  2. 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. 3. @dgomezg Session  Data:  State  of  the  art. • Sometimes  you  need/want  to  keep  data  from   the  user
  4. 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. 5. @dgomezg Scalability:  Clustering,  PASS  and     Cloud
  6. 6. @dgomezg Session  Data:  Caveats • Data  should  be  Serializable   • Servlet  Container  specific   • Implementation   • Persistent  storage  configuration.
  7. 7. @dgomezg Spring  session  motivation • Provide  a  mechanism  to  store  &  configure   session  data  handling
  8. 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. 9. @dgomezg INTRODUCING   SPRING  SESSION 9
  10. 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. 11. @dgomezg Architecture SessionRepositoryFilter Other  filters DispatcherServlet HttpRequestWrapper HttpSessionWrapper Transparently  replaces     HttpRequest  &  HttpSession
  12. 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. 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. 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. 15. @dgomezg SessionRepositoryFilter Bootstraps  Spring  Session  architecture   Servlet  3.0:    Use  AbstractHttpSessionApplicationInitializer   public class Initializer
 extends AbstractHttpSessionApplicationInitializer {
 
 public Initializer() {
 super(Config.class);
 }
 }
  16. 16. @dgomezg The  Big  Picture
  17. 17. @dgomezg USING  SPRING  SESSION  IN  YOUR   APPLICATION 17
  18. 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. 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. 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. 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. 22. @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
  23. 23. @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  
  24. 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. 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. 26. @dgomezg Step  5:  Bootstrap  SpringSession public class Initializer
 extends AbstractHttpSessionApplicationInitializer {
 
 public Initializer() {
 super(Config.class);
 }
 } Define  a  DelegatingFilterProxy  with  specific  name   springSessionRepositoryFilter
  27. 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. 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. 29. @dgomezg FURTHER  CUSTOMIZATION 29
  30. 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. 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. 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. 33. @dgomezg CookieSessionStrategy Default  strategy  on  RedisHttpSessionConfiguration   Sets  a  Cookie  with  the  session  ID.
  34. 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. 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. 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. 37. @dgomezg USE  CASE  1   CHANGE  PERSISTENCE  STORE 37
  38. 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. 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. 40. @dgomezg USE  CASE  2   MULTIPLE  USER  SESSIONS 40
  41. 41. @dgomezg Multiple  Session  Handling Session  id  is  :   1)  exchanged  with  the  client  via  CookieSessionStrategy   2)  which  is  a  MultipleSessionStrategy
  42. 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. 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. 44. @dgomezg Session  selection Specific  Session  selected  by  parameter  ?_s=#alias   http://localhost:8080/?_s=0  
  45. 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. 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. 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. 48. @dgomezg USE  CASE  3   RESTORING  STATE  TO  RESTFUL  APIS 48
  49. 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. 50. @dgomezg HeaderHttpSessionStrategy Uses  an  specific  header  in  Response  to  return   session  ID @Bean
 public HttpSessionStrategy httpSessionStrategy() {
 return new HeaderHttpSessionStrategy();
 }
  51. 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. 52. @dgomezg HeaderHttpSessionStrategy Use  an  HeaderHttpSessionStrategy @Bean
 public HttpSessionStrategy httpSessionStrategy() {
 return new HeaderHttpSessionStrategy();
 }
  53. 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. 54. @dgomezg CONCLUSIONS 54
  55. 55. @dgomezg Conclusions •HttpSession  not  container  dependant   •Implementation   •Configuration   •Persistent  store  easily  configurable   •Transparent  for  the  developer     •SpringSessionFilter,     •HttpServletRequest/HttpSession  Wrappers
  56. 56. @dgomezg THANKS! 56 Reach  me  on dgomezg@autentia.com @dgomezg Resources Spring  guides Spring  samples  repository

×