I have a problem with my personal project , I try to use Spring boot / redis to store all session and auth user . My application works fine except it clear all SercurityContext auth user when I restart my Spring boot app and I can not call to my api anymore.
My error log :
rg.springframework.data.redis.serializer.SerializationException: Cannot deserialize at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:108) ~[spring-data-redis-3.2.0.jar:3.2.0] at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:380) ~[spring-data-redis-3.2.0.jar:3.2.0] at org.springframework.data.redis.core.AbstractOperations.deserializeHashMap(AbstractOperations.java:324) ~[spring-data-redis-3.2.0.jar:3.2.0] at org.springframework.data.redis.core.DefaultHashOperations.entries(DefaultHashOperations.java:237) ~[spring-data-redis-3.2.0.jar:3.2.0]java.lang.IllegalStateException: Could not identify any active SessionFactory having UUID 9ff9b616-141b-4520-9d8c-7491441ecc10
After several days research , I think I need implement my custom SecurityContextRepository
@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(requests -> requests .requestMatchers("/" + apiPath +"/public/**").permitAll() .requestMatchers("/" + apiPath +"/**").authenticated() .requestMatchers("/swagger-ui/**").permitAll() .requestMatchers("/v3/api-docs/**").permitAll()) .csrf(AbstractHttpConfigurer::disable) .sessionManagement(session -> session .maximumSessions(1) .maxSessionsPreventsLogin(true) ) .securityContext(security -> security .securityContextRepository(MyCustomSecurityContextRepository()) // I think I need implement this ) .httpBasic(Customizer.withDefaults()); return http.build(); }@PostMapping("/public/user/login") public ResponseEntity<APIResponseDTO<Void>> login(HttpSession session, @RequestParam String username, @RequestParam String password) { try { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(username, password)); SecurityContextHolder.getContext().setAuthentication(authentication); userDetails = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); session.setAttribute("USER", userDetails); session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext()); } catch (BadCredentialsException e) { } } }}
Here is my MyCustomSecurityContextRepository . But It still have a same error
public class MyCustomSecurityContextRepositoryimplements SecurityContextRepository { private final HttpSessionSecurityContextRepository delegate; private final RedisTemplate<String, SecurityContext> redisTemplate; public MyCustomSecurityContextRepository(RedisTemplate<String, SecurityContext> redisTemplate) { this.delegate = new HttpSessionSecurityContextRepository(); this.redisTemplate = redisTemplate; } @Override public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) { // Attempt to load SecurityContext from Redis SecurityContext context = redisTemplate.opsForValue().get("securityContext:" + requestResponseHolder.getRequest().getSession().getId()); // If not found in Redis, delegate to the default implementation if (context == null) { context = delegate.loadContext(requestResponseHolder); } return context; } @Override public DeferredSecurityContext loadDeferredContext(HttpServletRequest request) { return SecurityContextRepository.super.loadDeferredContext(request); } @Override public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) { // Save SecurityContext to Redis redisTemplate.opsForValue().set("securityContext:" + request.getSession().getId(), context); // Delegate to the default implementation delegate.saveContext(context, request, response); } @Override public boolean containsContext(HttpServletRequest request) { // Check if SecurityContext is present in Redis return redisTemplate.hasKey("securityContext:" + request.getSession().getId()) || delegate.containsContext(request); }}
My expectation is when I try to restart my spring boot , User still have authenticate and call my api normally . Really sr for my bad english