本文介绍了如何从多个服务器获取与 Spring Security 和 Spring Session 相同的会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉我的英语还是不太好.请耐心等待,我希望你能理解我的问题..

我有两个网络服务器.(每个网络应用都是一样的)

Web 服务器共享一台 redis 服务器.我使用 Spring Security 和 Spring Session.当我登录第一台服务器并访问第二台服务器时,我想自动登录第二台服务器,但没有.

我猜是因为session id与不同的服务器ip不同.

  • 如何获得相同的会话 ID?

WEB.XML

<!-- 加载 Spring Security 配置文件 --><上下文参数><param-name>contextConfigLocation</param-name><参数值>/WEB-INF/spring/root-context.xml,/WEB-INF/spring/spring-security.xml,/WEB-INF/spring/jedis.xml</参数值></context-param><!-- 创建所有 Servlet 和过滤器共享的 Spring Container --><监听器><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></监听器><!-- 处理应用程序请求--><小服务程序><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><启动时加载>1</启动时加载><servlet-mapping><servlet-name>appServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 编码--><过滤器><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>编码</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-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></过滤器映射><!-- 会话过滤器--><过滤器><filter-name>springSessionRepositoryFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></过滤器><过滤器映射><filter-name>springSessionRepositoryFilter</filter-name><url-pattern>/*</url-pattern></过滤器映射><!-- Spring Security --><过滤器><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></过滤器><过滤器映射><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></过滤器映射>

jedis.xml

<property name="hostName" value=""<!-- 我的服务器 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><!-- 字符串序列化器,使 redis key 更易读 --><bean id="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer"/><!-- redis 模板定义--><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 auto-config="true" ><session-management session-fixation-protection="changeSessionId"><concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/><!-- 我无法清楚地理解这个元素--></会话管理><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"/><表单登录登录页面=/"authentication-success-handler-ref="loginSuccessHandler"authentication-failure-handler-ref="loginFailureHandler"始终使用默认目标 =真"用户名参数=j_username"密码参数=j_password"/><!-- default-target-url="/board" --><logout logout-success-url="/" invalidate-session="true" delete-cookies="true"/></http><认证管理器><authentication-provider user-service-ref="userDetailsS​​ervice"/></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="userDetailsS​​ervice" class="......UserDetailsS​​erviceImpl"><beans:property name="sqlSession" ref="sqlSession"/></beans:bean>
解决方案

这似乎是一个老问题.但是,看起来有可能实现想要的行为.查看 http://docs.spring.io/spring-session/docs/current/reference/html5/guides/security.html 了解更多详情

创建Redis bean

<property name="port" value="${app.redis.port}"/><property name="hostName" value="${app.redis.hostname}"/></bean><context:annotation-config/><豆class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>

以上将创建与 Redis 服务器的连接,并将创建一个名为 springSessionRepositoryFilter 的 bean,它将替换常规的 HttpSession 实现.>

设置弹簧安全

可以通过使用 org.springframework.security.web.FilterChainProxy 创建 spring 过滤器即:

<filter-chain-map request-matcher="ant"><filter-chain pattern="/somelocation/" filters="none"/><filter-chain pattern="/someotherlocation"过滤器="springSessionRepositoryFilter, somemorespring 过滤器"/></filter-chain-map></b:bean>

注意:spring security 过滤器的顺序很重要,本答案不包括在内.但是为了能够使用 spring Session和 redis,第一个过滤器必须是 springSessionRepositoryFilter.有关更多信息,请访问 http://docs.spring.io/spring-security/site/docs/3.0.x/reference/security-filter-chain.html

设置Http会话

编辑web.xml

<filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></过滤器><过滤器映射><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></过滤器映射>

这将允许 tomcat 在任何过滤器之前使用 springSecurityFilterChain,因此它将允许 springSessionRepositoryFilter 成为第一个过滤器.这将导致 Spring session 魔法从 redis db

获取 session

使用 Spring session + spring security 而不使用 custom spring filters 可以在 http://www.jayway.com/2015/05/31/scaling-out-with-spring-session/

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>
解决方案

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.FilterChainProxyi.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/

这篇关于如何从多个服务器获取与 Spring Security 和 Spring Session 相同的会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-22 11:40