9

I need to be able to store the HTTP Session in a relational database in order to do stateless load balancing of my front-end users across multiple front-end servers. How can I achieve this in Spring 4?

I see how one can do this with Redis, however there does not appear to be documentation on how to do this with a relational database e.g. Postgres.

BestPractices
  • 12,738
  • 29
  • 96
  • 140
  • 1
    Possible duplicate of: http://stackoverflow.com/questions/20507749/how-can-i-make-the-spring-security-stores-the-http-session-in-database-so-i-can – riddle_me_this Jul 16 '15 at 19:51

3 Answers3

21

With Spring Session (it transparently will override HttpSessions from Java EE) you can just take SessionRepository interface and implement it with your custom ex. JdbcSessionRepository. It is kind of easy to do. When you have your implementation, then just add manually (you don't need @EnableRedisHttpSession annotation) created filter to filter chain, like bellow:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

   //other stuff...

   @Autowired
   private SessionRepository<ExpiringSession> sessionRepository;

   private HttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy(); // or HeaderHttpSessionStrategy

   @Bean
   public SessionRepository<ExpiringSession> sessionRepository() {
       return new JdbcSessionRepository();
   }

   @Override
   protected void configure(HttpSecurity http) throws Exception {
       super.configure(http);
       SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);
       sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
       http
            .addFilterBefore(sessionRepositoryFilter, ChannelProcessingFilter.class);
   }
}

Here you have how SessionRepository interface looks like. It has only 4 methods to implement. For how to create Session object, you can look in MapSessionRepository and MapSession implementation (or RedisOperationsSessionRepository and RedisSession).

public interface SessionRepository<S extends Session> {
   S createSession();
   void save(S session);
   S getSession(String id);
   void delete(String id);
}

Example solution https://github.com/Mati20041/spring-session-jpa-repository

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Mati
  • 2,476
  • 2
  • 17
  • 24
  • Thanks, can you please complete this with an implementation of the JDBCSessionRepository? – BestPractices Jul 17 '15 at 13:33
  • I can give you later an example made in Spring Data JPA (with SQL Database as Datasource), if that will please you. – Mati Jul 17 '15 at 13:54
  • yes, and if u can show what the database table definition is, that would be helpful. – BestPractices Jul 17 '15 at 15:18
  • Here I have uploaded sample solution to your problem, maybe it is not as fancy as it can be, but works. https://github.com/Mati20041/spring-session-jpa-repository . It uses in memory database for the sake of simplicity, but you can change it easily in application.properties. – Mati Jul 17 '15 at 15:53
  • Mati, one question, I was implement your code on my App. When I enter for the first time I have 1 cookie "SESSION", but when I login (using spring security) I have the security cookie "JSESSION". This is correct to clustered enviroment? or I need just the JSESSION cookie and store it over the DB? – HolloW Sep 05 '15 at 17:03
  • When you deal with spring-session, use SESSION, not JSESSION. JSESSION probably comes from server(tomcat, jetty or sth), not spring. If you run my demo, you can see (for example in firefox developer tools -> network) that it does not send JSESSION cookie. – Mati Sep 05 '15 at 20:30
  • Hi Mati, thanks for your answer, i have been working session management, and above answer worked for alot, but i am getting this error on browser 'Invalid CSRF Token was found on the request parameter **_csrf or header X-CSRF-TOKEN** – Ravi H Jan 28 '16 at 13:12
  • @Ravi. Hi Ravi, CSRF-TOKEN is (or 'should be' AFAIK) be different kind of problem that is not related to this topic. It is from security package and you can read more about it here: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html or I would suggest this article, which covers how you can handle it in other ways (or just turn it off, but that might be a security flaw) https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii – Mati Jan 29 '16 at 12:39
  • Hi Mati, thanks for response, i solved the problem by configuring SecurityIntializer class which is extends to AbstractSecurityWebApplicationInitializer – Ravi H Jan 29 '16 at 12:48
  • I am getting "No qualifying bean of type 'com.fastcheck.timesheet.common.session.SpringSessionRepository' available' error. Am I doing something wrong? Follow the link for source code https://github.com/jpavanaryan/FastCheck/blob/FormLogin/src/main/java/com/fastcheck/timesheet/common/session/SessionRepositoryImpl.java –  Jul 25 '17 at 16:51
0

Now spring boot supports by 'spring-session-jdbc'. You can save session into db with less code. For more example you can look at https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-jdbc.html#httpsession-jdbc-boot-sample

-1

Just slap Spring Session on it, and you're done. Adding a Redis client bean and annotating a configuration class with @EnableRedisHttpSession is all you need.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
  • As mentioned in the question, I dont wish to do this with Redis. I wish to do this in the database I already have, Postgres. – BestPractices Jul 14 '15 at 16:37
  • @BestPractices Specifically avoiding Redis wasn't a particularly clear requirement. That said, I believe Spring Session supports a JDBC repository (and adding one would be trivial if it doesn't). – chrylis -cautiouslyoptimistic- Jul 14 '15 at 16:39