Spring 与 Spring 安全性的会话创建了两个会话
Spring Session with Spring Security creates two sessions
我有一个 Spring 4.1 网络应用程序,我使用 spring-security 和 spring 会话,spring 会话我想与 websockets 一起使用以保持会话只要 websocket 正常工作就不会超时。
一切正常,但我发现我显然有两个会话 运行,一个用于 spring 安全,一个用于 spring 会话。
这是我的 session.xml:
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="localhost"/>
<property name="port" value="6379" />
</bean>
<bean class="org.springframework.session.data.redis.RedisOperationsSessionRepository" name="sessionRepository" >
<constructor-arg name="redisConnectionFactory" ref="jedisConnFactory" />
<!--<property name="defaultMaxInactiveInterval" value="60" />-->
</bean>
<bean class="org.springframework.session.web.http.HeaderHttpSessionStrategy" name="sessionStrategy" />
<bean name="springSessionRepositoryFilter" class="org.springframework.session.web.http.SessionRepositoryFilter">
<constructor-arg name="sessionRepository" ref="sessionRepository" />
</bean>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" >
<property name="httpSessionStrategy" ref="sessionStrategy"/>
</bean>
这是我的 security.xml:
<!-- Security -->
<bean id="userDetailsService" class="com.fg.ts.base.security.userdetails.CustomUserDetailsService" />
<bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<constructor-arg value="${encoder.password}" />
</bean>
<sec:authentication-manager id="authenticationManager">
<sec:authentication-provider user-service-ref="userDetailsService">
<sec:password-encoder ref="passwordEncoder" />
</sec:authentication-provider>
</sec:authentication-manager>
<sec:global-method-security pre-post-annotations="enabled" secured-annotations="disabled"
jsr250-annotations="enabled" authentication-manager-ref="authenticationManager" />
<!-- Exclude the resources+error+auth pages from security filter -->
<sec:http pattern="/javax.faces.resource/**" security="none" />
<sec:http pattern="/images/**" security="none" />
<sec:http pattern="/css/**" security="none" />
<sec:http pattern="/ico/**" security="none" />
<sec:http pattern="/lib/**" security="none" />
<sec:http pattern="/js/**" security="none" />
<sec:http pattern="/auth/**" security="none" />
<sec:http pattern="/error/**" security="none" />
<sec:http pattern="/api/concordancer/search/**" security="none" />
<sec:http pattern="/concordancer/search" security="none"/>
<sec:http pattern="/assets/cdSearch.xhtml" security="none"/>
<sec:http pattern="/api/tmGroup/**" security="none"/>
<sec:http pattern="/api/reports/download/**" security="none"/>
<sec:http pattern="/api/socket/tasks/info/**" security="none"/>
<!-- Security Configuration for Faces Pages -->
<!-- Start Customization for Faces -->
<!-- ***************************** -->
<!-- Failure Login Handler -->
<bean id="authenticationFailureHandler" class="com.fg.ts.web.util.security.LoginFailureHandler">
<property name="defaultFailureUrl" value="/auth/login" />
</bean>
<!-- Faces Redirect -->
<bean id="facesRedirectStrategy" class="com.fg.ts.web.util.security.FacesRedirectStrategy">
<property name="invalidSessionUrl" value="/auth/login/sessionExpired" />
</bean>
<!-- Shared Objects -->
<bean id="securityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- Session Authentication Strategy -->
<bean id="sessionFixationAuthenticationStrategy" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
<bean id="registerSessionStrategy" class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
</bean>
<bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg name="delegateStrategies">
<list>
<!-- <ref bean="concurrentSessionStrategy" /> -->
<ref bean="sessionFixationAuthenticationStrategy" />
<ref bean="registerSessionStrategy" />
</list>
</constructor-arg>
</bean>
<!-- Remember-Me Service -->
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<constructor-arg name="key" value="${encoder.password}" />
<constructor-arg name="userDetailsService" ref="userDetailsService" />
<property name="parameter" value="j_remember_me" />
<property name="cookieName" value="TMS_REME" />
</bean>
<!-- Filters -->
<bean id="usernamePasswordAuthenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy" />
<property name="rememberMeServices" ref="rememberMeServices" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</bean>
<bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
<constructor-arg name="securityContextRepository" ref="securityContextRepository" />
<constructor-arg name="sessionStrategy" ref="sessionAuthenticationStrategy" />
<property name="invalidSessionStrategy" ref="facesRedirectStrategy" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</bean>
<bean id="concurrentSessionFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<constructor-arg name="expiredUrl" value="/auth/login/expiredDueToConcurrentAccess" />
<property name="redirectStrategy" ref="facesRedirectStrategy" />
</bean>
<bean id="authEntryPoint" class="com.fg.ts.web.util.security.FacesLoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/auth/login"/>
</bean>
<!-- End Customization for Faces -->
<!-- ***************************** -->
<sec:http use-expressions="true" disable-url-rewriting="true" authentication-manager-ref="authenticationManager"
entry-point-ref="authEntryPoint"> <!--security-context-repository-ref="securityContextRepository"-->
<sec:http-basic />
<sec:custom-filter ref="usernamePasswordAuthenticationFilter" before="FORM_LOGIN_FILTER" />
<sec:custom-filter ref="sessionManagementFilter" position="SESSION_MANAGEMENT_FILTER" />
<sec:anonymous />
<sec:remember-me key="${encoder.password}" services-ref="rememberMeServices" />
<sec:form-login login-page="/auth/login" authentication-failure-handler-ref="authenticationFailureHandler" />
<sec:logout logout-url="/logout" invalidate-session="true" delete-cookies="TMS_SES,TMS_REME"
logout-success-url="/auth/login" />
<sec:session-management session-fixation-protection="none" />
<!-- General Access Control -->
<sec:intercept-url pattern="/projects/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/assets/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/setup/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/tm/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/termBase/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/quality/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/editor/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/api/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
</sec:http>
如何让 spring 安全使用 spring-session 创建的会话?
我发现了问题,原因是在 FilterChain 中,springSecurityFilterChain
Filter 总是在 springSessionRepositoryFilter
之前先加载,所以 Spring Session 还没有创建,所以安全过滤器创建了它自己的。
发生这种情况是因为我的 springSessionRepositoryFilter
是专门为每个 servlet 配置的,如下所示:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<servlet-name>mvc-dispatcher</servlet-name>
</filter-mapping>
但是当我删除它并使它成为一个全局过滤器时,它就可以工作了,就像这样:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我有一个 Spring 4.1 网络应用程序,我使用 spring-security 和 spring 会话,spring 会话我想与 websockets 一起使用以保持会话只要 websocket 正常工作就不会超时。
一切正常,但我发现我显然有两个会话 运行,一个用于 spring 安全,一个用于 spring 会话。
这是我的 session.xml:
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="localhost"/>
<property name="port" value="6379" />
</bean>
<bean class="org.springframework.session.data.redis.RedisOperationsSessionRepository" name="sessionRepository" >
<constructor-arg name="redisConnectionFactory" ref="jedisConnFactory" />
<!--<property name="defaultMaxInactiveInterval" value="60" />-->
</bean>
<bean class="org.springframework.session.web.http.HeaderHttpSessionStrategy" name="sessionStrategy" />
<bean name="springSessionRepositoryFilter" class="org.springframework.session.web.http.SessionRepositoryFilter">
<constructor-arg name="sessionRepository" ref="sessionRepository" />
</bean>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" >
<property name="httpSessionStrategy" ref="sessionStrategy"/>
</bean>
这是我的 security.xml:
<!-- Security -->
<bean id="userDetailsService" class="com.fg.ts.base.security.userdetails.CustomUserDetailsService" />
<bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<constructor-arg value="${encoder.password}" />
</bean>
<sec:authentication-manager id="authenticationManager">
<sec:authentication-provider user-service-ref="userDetailsService">
<sec:password-encoder ref="passwordEncoder" />
</sec:authentication-provider>
</sec:authentication-manager>
<sec:global-method-security pre-post-annotations="enabled" secured-annotations="disabled"
jsr250-annotations="enabled" authentication-manager-ref="authenticationManager" />
<!-- Exclude the resources+error+auth pages from security filter -->
<sec:http pattern="/javax.faces.resource/**" security="none" />
<sec:http pattern="/images/**" security="none" />
<sec:http pattern="/css/**" security="none" />
<sec:http pattern="/ico/**" security="none" />
<sec:http pattern="/lib/**" security="none" />
<sec:http pattern="/js/**" security="none" />
<sec:http pattern="/auth/**" security="none" />
<sec:http pattern="/error/**" security="none" />
<sec:http pattern="/api/concordancer/search/**" security="none" />
<sec:http pattern="/concordancer/search" security="none"/>
<sec:http pattern="/assets/cdSearch.xhtml" security="none"/>
<sec:http pattern="/api/tmGroup/**" security="none"/>
<sec:http pattern="/api/reports/download/**" security="none"/>
<sec:http pattern="/api/socket/tasks/info/**" security="none"/>
<!-- Security Configuration for Faces Pages -->
<!-- Start Customization for Faces -->
<!-- ***************************** -->
<!-- Failure Login Handler -->
<bean id="authenticationFailureHandler" class="com.fg.ts.web.util.security.LoginFailureHandler">
<property name="defaultFailureUrl" value="/auth/login" />
</bean>
<!-- Faces Redirect -->
<bean id="facesRedirectStrategy" class="com.fg.ts.web.util.security.FacesRedirectStrategy">
<property name="invalidSessionUrl" value="/auth/login/sessionExpired" />
</bean>
<!-- Shared Objects -->
<bean id="securityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- Session Authentication Strategy -->
<bean id="sessionFixationAuthenticationStrategy" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
<bean id="registerSessionStrategy" class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
</bean>
<bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg name="delegateStrategies">
<list>
<!-- <ref bean="concurrentSessionStrategy" /> -->
<ref bean="sessionFixationAuthenticationStrategy" />
<ref bean="registerSessionStrategy" />
</list>
</constructor-arg>
</bean>
<!-- Remember-Me Service -->
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<constructor-arg name="key" value="${encoder.password}" />
<constructor-arg name="userDetailsService" ref="userDetailsService" />
<property name="parameter" value="j_remember_me" />
<property name="cookieName" value="TMS_REME" />
</bean>
<!-- Filters -->
<bean id="usernamePasswordAuthenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy" />
<property name="rememberMeServices" ref="rememberMeServices" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</bean>
<bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
<constructor-arg name="securityContextRepository" ref="securityContextRepository" />
<constructor-arg name="sessionStrategy" ref="sessionAuthenticationStrategy" />
<property name="invalidSessionStrategy" ref="facesRedirectStrategy" />
<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</bean>
<bean id="concurrentSessionFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<constructor-arg name="expiredUrl" value="/auth/login/expiredDueToConcurrentAccess" />
<property name="redirectStrategy" ref="facesRedirectStrategy" />
</bean>
<bean id="authEntryPoint" class="com.fg.ts.web.util.security.FacesLoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/auth/login"/>
</bean>
<!-- End Customization for Faces -->
<!-- ***************************** -->
<sec:http use-expressions="true" disable-url-rewriting="true" authentication-manager-ref="authenticationManager"
entry-point-ref="authEntryPoint"> <!--security-context-repository-ref="securityContextRepository"-->
<sec:http-basic />
<sec:custom-filter ref="usernamePasswordAuthenticationFilter" before="FORM_LOGIN_FILTER" />
<sec:custom-filter ref="sessionManagementFilter" position="SESSION_MANAGEMENT_FILTER" />
<sec:anonymous />
<sec:remember-me key="${encoder.password}" services-ref="rememberMeServices" />
<sec:form-login login-page="/auth/login" authentication-failure-handler-ref="authenticationFailureHandler" />
<sec:logout logout-url="/logout" invalidate-session="true" delete-cookies="TMS_SES,TMS_REME"
logout-success-url="/auth/login" />
<sec:session-management session-fixation-protection="none" />
<!-- General Access Control -->
<sec:intercept-url pattern="/projects/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/assets/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/setup/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/tm/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/termBase/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/quality/**" access="hasAnyRole('ROLE_ADMIN','ROLE_PM')" />
<sec:intercept-url pattern="/editor/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/api/**" access="isAuthenticated()" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
</sec:http>
如何让 spring 安全使用 spring-session 创建的会话?
我发现了问题,原因是在 FilterChain 中,springSecurityFilterChain
Filter 总是在 springSessionRepositoryFilter
之前先加载,所以 Spring Session 还没有创建,所以安全过滤器创建了它自己的。
发生这种情况是因为我的 springSessionRepositoryFilter
是专门为每个 servlet 配置的,如下所示:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<servlet-name>mvc-dispatcher</servlet-name>
</filter-mapping>
但是当我删除它并使它成为一个全局过滤器时,它就可以工作了,就像这样:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>