How to prevent Redis from being used for anonymous user sessions

I have this sample application:

package com.example.session; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication public class DemoRedisDataSessionApplication { @Configuration @EnableWebSecurity @EnableRedisHttpSession(redisNamespace = "demo-redis-data-session") public static class AppConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("user").password("0000").roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin().and() .authorizeRequests().antMatchers("/ping").permitAll().and() .authorizeRequests().anyRequest().fullyAuthenticated(); } } @RestController public static class AppController { @GetMapping("/ping") public String ping() { return "pong"; } @GetMapping("/secured") public String secured() { return "secured"; } } public static void main(String[] args) { SpringApplication.run(DemoRedisDataSessionApplication.class, args); } } 

When I clicked /secured , I get 302 redirected to the /login form, and this is what I expect if I have not logged in, but I get some unwanted entries in Redis:

127.0.0.1:6379> keys * 1) "spring:session:demo-redis-data-session:sessions:expires:dbb124b9-c37d-454c-8d67-409f28cb88a6" 2) "spring:session:demo-redis-data-session:expirations:1515426060000" 3) "spring:session:demo-redis-data-session:sessions:dbb124b9-c37d-454c-8d67-409f28cb88a6"

I don’t want to create this data for every anonymous user (reading crawler), so is there a way to prevent these Redis entries from entering a secure endpoint / page with an anonymous user?

Additional data used for this example project

docker-compose.yml

version: "2" services: redis: image: redis ports: - "6379:6379"

Spring Boot Version

1.5.9.RELEASE

+5
source share
1 answer

This is not an optimal solution since it only creates one session for all crawlers, but at least I don't get Redis from an unwanted session.

 import lombok.extern.log4j.Log4j; import org.springframework.session.Session; import org.springframework.session.SessionRepository; import org.springframework.session.web.http.CookieHttpSessionStrategy; import org.springframework.session.web.http.MultiHttpSessionStrategy; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Log4j @Component public class CrawlerManagerSessionStrategyWrapper implements MultiHttpSessionStrategy { private CookieHttpSessionStrategy delegate; private volatile String crawlerSessionId; public CrawlerManagerSessionStrategyWrapper() { this.delegate = new CookieHttpSessionStrategy(); } public String getRequestedSessionId(HttpServletRequest request) { String sessionId = getSessionIdForCrawler(request); if (sessionId != null) return sessionId; else { return delegate.getRequestedSessionId(request); } } public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) { delegate.onNewSession(session, request, response); if (isCrawler(request)) { crawlerSessionId = session.getId(); } } public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) { delegate.onInvalidateSession(request, response); } public HttpServletRequest wrapRequest(HttpServletRequest request, HttpServletResponse response) { return request; } public HttpServletResponse wrapResponse(HttpServletRequest request, HttpServletResponse response) { return response; } private String getSessionIdForCrawler(HttpServletRequest request) { if (isCrawler(request)) { SessionRepository<Session> repo = (SessionRepository<Session>) request.getAttribute(SessionRepository.class.getName()); if (crawlerSessionId != null && repo != null) { Session session = repo.getSession(crawlerSessionId); if (session != null) { return crawlerSessionId; } } } return null; } private boolean isCrawler(HttpServletRequest request) { // Here goes the logic to understand if the request comes from a crawler, for example by checking the user agent. return true; } } 

The only thing that needs to be implemented is the isCrawler method to indicate if the request comes from the crawler.

0
source

Source: https://habr.com/ru/post/1274577/


All Articles