How to get same session with Spring Security and Spring Session From multiple server

14,670

It seems like an old question. But, It looks like is possible to achieve the wanted behavior. Check out http://docs.spring.io/spring-session/docs/current/reference/html5/guides/security.html for more details

Create redis beans

<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="port" value="${app.redis.port}" />
    <property name="hostName" value="${app.redis.hostname}" />
</bean>

<context:annotation-config />
<bean
    class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>

The above will create connection to Redis server with and will create a bean named springSessionRepositoryFilter which will replace the regular HttpSession implementation.

Setup spring security

One can create spring filter via using org.springframework.security.web.FilterChainProxy i.e :

<b:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <filter-chain-map request-matcher="ant">
         <filter-chain pattern="/somelocation/" filters="none" />
         <filter-chain pattern="/someotherlocation"
            filters="springSessionRepositoryFilter, somemorespring filters"/>
    </filter-chain-map>
</b:bean>

Note: The order of the filter for spring security is important and is not cover in this answer. BUT in order to be able to work with spring Session and redis, the very first filter has be to springSessionRepositoryFilter. More info about that can be found at http://docs.spring.io/spring-security/site/docs/3.0.x/reference/security-filter-chain.html

Setting up Http session

Edit web.xml

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-  class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
 <filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

This will allow tomcat to use springSecurityFilterChain before any filter and therefor it will allow to springSessionRepositoryFilter to be the first filter. Which will result with the Spring session magic to get the session from redis db

Using Spring session + spring security with out custom spring filters can be found at http://www.jayway.com/2015/05/31/scaling-out-with-spring-session/

Share:
14,670
Lee이민규
Author by

Lee이민규

Updated on June 12, 2022

Comments

  • Lee이민규
    Lee이민규 almost 2 years

    I'm sorry that my english is still not so good. Please bear with me, I hope you can understand my question..


    I have two web servers. (each web application is same)

    Web servers are sharing one redis server. And I use Spring Security and Spring Session. When I login first server and access second server, I want to login second server automatically, but it isn't.

    I guess, because session id is different from different server ip.

    • how to get same session id ?

    WEB.XML

    <!-- The definition of the Root Spring Container shared by all Servlets 
        and Filters -->
    <!-- Loads Spring Security config file -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/root-context.xml,
            /WEB-INF/spring/spring-security.xml,
            /WEB-INF/spring/jedis.xml
                </param-value>
    </context-param>
    
    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- Processes application requests -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- Encoding -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- Session Filter -->
    <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>
    
    <!-- Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    jedis.xml

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value=""<!-- My Server IP --> />
        <property name="port" value="6379" />
        <property name="poolConfig" ref="redisPoolConfig" />
    </bean>
    
    
    <bean id="redisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="testOnBorrow" value="true" />
        <property name="minEvictableIdleTimeMillis" value="60000" />
        <property name="softMinEvictableIdleTimeMillis" value="1800000" />
        <property name="numTestsPerEvictionRun" value="-1" />
        <property name="testOnReturn" value="false" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
    </bean>
    
    <!-- string serializer to make redis key more readible  -->
    <bean id="stringRedisSerializer"
        class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    
    <!-- redis template definition  -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
    </bean>
    

    spring-security.xml

    <http pattern="/resources/**" security="none" />
    
    <http auto-config="true" >
        <session-management session-fixation-protection="changeSessionId">
            <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/> <!-- I couldn't clear understand of this element-->
        </session-management>
        <intercept-url pattern="/" access="ROLE_ANONYMOUS, ROLE_USER" />
        <intercept-url pattern="/perBoard" access="ROLE_ANONYMOUS, ROLE_USER" />
        <intercept-url pattern="/per" access="ROLE_ANONYMOUS, ROLE_USER" />
        <intercept-url pattern="/perSearchTag" access="ROLE_ANONYMOUS, ROLE_USER" />
        <intercept-url pattern="/**" access="ROLE_USER" />
        <form-login login-page="/" 
                    authentication-success-handler-ref="loginSuccessHandler"
                    authentication-failure-handler-ref="loginFailureHandler"
                    always-use-default-target="true" 
                    username-parameter="j_username" 
                    password-parameter="j_password"/>
                    <!-- default-target-url="/board"  -->
        <logout logout-success-url="/" invalidate-session="true" delete-cookies="true" />
    </http>
    
    <authentication-manager>
        <authentication-provider user-service-ref="userDetailsService" />
    </authentication-manager>
    
    <beans:bean id="loginSuccessHandler" class=".......LoginSuccessHandler">
        <beans:property name="sqlSession" ref="sqlSession" />
    </beans:bean>
    <beans:bean id="loginFailureHandler" class=".......LoginFailureHandler" />
    <beans:bean id="userDetailsService" class="......UserDetailsServiceImpl">
        <beans:property name="sqlSession" ref="sqlSession" />
    </beans:bean>
    
  • dragonalvaro
    dragonalvaro over 7 years
    @durron597 I have the same problems. But I don't have any clue on what's going on. I did the tutorial but they aren't sharing the same session. They are creating a new one.