Hey all,
We have Spring
project which uses Spring security
. We have defined the security filters by defining
<b:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
whith filter-chain-map
and in the web.xml
we do
<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>
and it all works well :). Now when hooking up Spring session
with redis
according to the doc
the next following lines
<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
create a filter
named springSessionRepositoryFilter
. So basically what we did is in every custom filter-chain
we add that filter to be the very first filter . i.e:
<b:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<filter-chain-map request-matcher="ant">
<filter-chain pattern="/api/someapieformobilelogin" filters="none" /> <!-- no filter on login -->
<filter-chain pattern="/api/**"
filters="springSessionRepositoryFilter, securityContextFilter,and some other spring security filter />
<filter-chain pattern="/**"
filters="springSessionRepositoryFilter, securityContextFilter,and some other spring security filter />
The results: the app seems to work good and also monitoring
via redis-cli
shows the spring
is communicating with redis
.
Does the use of springSessionRepositoryFilter
inside the filter-chain
is ok? or we abused the filtering system?
Thanks,
Oak
It seems that above will not work for the case one wants to Authenticate
the user from code i.e
Authentication authentication = authenticationManager
.authenticate(authenticationToken);
SecurityContext securityContext = SecurityContextHolder
.getContext();
securityContext.setAuthentication(authentication);
will failed. Maybe because its not enough to run it via filter-chain
of org.springframework.security.web.FilterChainProxy
.
What do you think on run it as filter
in web.xml
?
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</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>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The above will force running springSessionRepositoryFilter
before springSecurityFilterChain
but in this example org.springframework.web.filter.DelegatingFilterProxy
is being called twice. any other ways to make springSessionRepositoryFilter
run as a filter before out springSecurityFilterChain
filter?
According to my testing, springSessionRepositoryFilter
must run first. This is due the fact that springSessionRepositoryFilter
replaces the HttpSession
implementation. Here is my solution using xml
files.
<context:annotation-config />
<bean
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />
<bean
class="org.springframework.security.web.session.HttpSessionEventPublisher" />
<!-- end of seesion managment configuration -->
<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}" />
<property name="password" value="${app.redis.password}" />
<property name="usePool" value="true" />
</bean>
We use the combination of and RedisHttpSessionConfiguration because Spring Session does not yet provide XML Namespace support (see gh-104). This creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis. source
Now, as we have the session filter
named springSessionRepositoryFilter
it must run as the first filter because it replaces the HttpSession
implementation.
In order to do so, we declare it as the first filter in web.xml
. For more info about filters and filter's order checkout the docs
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</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>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/redis-cache.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Note that the first to run is springSessionRepositoryFilter
. But actully org.springframework.web.filter.DelegatingFilterProxy
class is running and it looks for the filter by the bean's name. So it search for the bean created by our early configurations.
reference
The extra line about the redis-cache.xml
are important as well. Otherwise our spring
application context
cannot know about our redis configuration
reference
It does not matter. From the Javadoc:
The SessionRepositoryFilter must be placed before any Filter that access the HttpSession or that might commit the response to ensure the session is overridden and persisted properly.
So long as you add springSessionRepositoryFilter
before anything that can commit the response or access the HttpSession
, you are fine. In the case of Spring Security the main thing you will want to ensure is that springSessionRepositoryFilter
is before the SecurityContextPersistenceFilter
. This can be done by including springSessionRepositoryFilter
within the container or within Spring Security's FilterChainProxy
(i.e. <filter-chain>
).
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