java 如何从多个服务器获取与 Spring Security 和 Spring Session 相同的会话

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28447414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 13:37:05  来源:igfitidea点击:

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

javaspringsessionspring-mvcspring-security

提问by Lee???

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 应用程序都相同)

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.

Web 服务器共享一台 redis 服务器。我使用 Spring Security 和 Spring Session。当我登录第一台服务器并访问第二台服务器时,我想自动登录第二台服务器,但事实并非如此。

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

我猜,因为会话 id 与不同的服务器 ip 不同。

  • how to get same session id ?
  • 如何获得相同的会话ID?

WEB.XML

网页.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

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

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>

回答by oak

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.htmlfor more details

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

Create redis beans

创建Redis bean

<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 Redisserver with and will create a bean named springSessionRepositoryFilterwhich will replace the regular HttpSessionimplementation.

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

Setup spring security

设置弹簧安全

One can create spring filtervia using org.springframework.security.web.FilterChainProxyi.e :

可以spring filter通过使用org.springframework.security.web.FilterChainProxyie创建:

<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 securityis 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

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

Setting up Http session

设置 Http 会话

Edit web.xml

编辑 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 tomcatto use springSecurityFilterChainbefore any filter and therefor it will allow to springSessionRepositoryFilterto be the first filter. Which will result with the Spring sessionmagic to get the sessionfrom redisdb

这将允许在任何过滤器之前tomcat使用springSecurityFilterChain,因此它将允许springSessionRepositoryFilter成为第一个过滤器。这将导致从dbSpring session获取的魔法sessionredis

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

使用Spring session + spring security带出来custom spring filters,可以发现http://www.jayway.com/2015/05/31/scaling-out-with-spring-session/