Spring Session Redis Demo
By Default Spring boot stores user session info in Server’s memory. If we have more than one instance of web application behind a load balancer, this will cause problem because the request has to be route to the same instance to retrieve session data. One solution is to use sticky session. Sticky session has many disadvantages. One of the disadvantage is servers may go down, the session data is lost.
Spring Session uses data store to store session data. So we can implement a stateless application. This is valuable in the cloud environment.
Spring Session supports many data store
Redis
JDBC
MongoDB
GemFire
The most popular store is Redis.
Start Redis Server To make it simple, we can start redis server as Docker container
1 docker run -d --rm -p 6379:6379 --name redis-demo redis
You can get into the container and execute redis-cli
to bring up the Redis CLI to interact with the Redis Contaienr
Maven Dependency 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency > <dependency > <groupId > org.springframework.session</groupId > <artifactId > spring-session-data-redis</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-security</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency >
Spring Session Configuration We need to set the redis server connection and Spring Session’s store type in application.properties
1 2 3 4 5 spring.redis.host=localhost spring.redis.port=6379 spring.redis.password= spring.session.store-type=redis
We also need to enable Redis session using @EnableRedisHttpSession
annotation
1 2 3 4 5 6 7 8 9 @SpringBootApplication @EnableRedisHttpSession public class SpringSessionRedisApplication { public static void main (String[] args) { SpringApplication.run(SpringSessionRedisApplication.class, args); } }
That is all we need for Spring Session Redis configuration.
Security Config We can define a regular user and admin user in Security Configuration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder () { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } @Override protected void configure (HttpSecurity http) throws Exception { http.formLogin().and() .authorizeRequests() .mvcMatchers("/" ).hasRole("USER" ) .anyRequest().authenticated(); } @Override protected void configure (AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user" ) .password(passwordEncoder().encode("password" )) .roles("USER" ) .and() .withUser("admin" ) .password(passwordEncoder().encode("password" )) .roles("ADMIN" ); } }
Controller This controller providers 3 endpoints. /setValue sets session attribute “foo” and /getValue gets “foo’ attribute value from session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @RestController public class HomeController { private static final Logger LOG = LoggerFactory.getLogger(HomeController.class); @GetMapping("/") public String home () { return "Home" ; } @GetMapping("/setValue/{val}") public String setValue (HttpServletRequest request, @PathVariable String val) { HttpSession session = request.getSession(); session.setAttribute("foo" , val); return "OK" ; } @GetMapping("/getValue") public String getValue (HttpServletRequest request) { HttpSession session = request.getSession(); if ( session.getAttribute("foo" ) != null ){ return session.getAttribute("foo" ).toString(); } return "Can't find Value" ; } }
Test We can login and set value using User and Admin account. Spring will store the session in Redis.
Use KEYS
command to check the keys set in redis:
1 2 3 4 5 6 7 8 9 10 11 127.0.0.1:6379> keys * 1) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:admin" 2) "spring:session:sessions:756cb785-5b04-43e3-99cf-0f82bb9d0767" 3) "spring:session:sessions:e4429c73-4d26-41d6-b598-b7c9b0dc2116" 4) "spring:session:expirations:1592599800000" 5) "spring:session:expirations:1592599860000" 6) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:user" 7) "spring:session:sessions:expires:dfb4e97c-681b-4710-8bd7-667f95621f0c" 8) "customer:-5656296892928562510" 9) "spring:session:sessions:dfb4e97c-681b-4710-8bd7-667f95621f0c" 10) "spring:session:sessions:expires:756cb785-5b04-43e3-99cf-0f82bb9d0767"
You can view the source code from Github: https://github.com/xinghua24/SpringBootExamples/tree/master/SpringSessionRedis
Reference