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.
<!-- 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>
<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>
<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>
Application servers are able to handle this scenario using "session replication". With session replication, each server will have a copy of the active users session. IF the first request goes to server A and second request goes to server B, it will be transparent to application code and end user.
Concurrent Session Control When a user that is already authenticated tries to authenticate again, the application can deal with that event in one of a few ways. It can either invalidate the active session of the user and authenticate the user again with a new session, or allow both sessions to exist concurrently.
SessionManagementFilter in Spring Security web. session. SessionManagementFilter. In XML configuration it's represented by a tag called <session-management />.
Default value is 30 minutes. If you are using spring boot, then as of version 1.3 it will automatically sync the value with the server. session. timeout property from the application configuration.
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
<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.
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
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With