<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.3.3.RELEASE</version>
</dependency>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<context:annotation-config/>
<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="7200"/>
bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
bean>
beans>
<bean id="sessionRegistry"
class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
<constructor-arg name="sessionRepository" ref="sessionRepository"/>
bean>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth2="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http security="none" pattern="/login.html" />
<security:http security="none" pattern="/failer.html" />
<security:http security="none" pattern="/api-docs" />
<security:http security="none" pattern="/loginController/loginFail"/>
<security:http use-expressions="false"
entry-point-ref="customAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager"
auto-config="false">
<security:access-denied-handler ref="accessDeniedHandler" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="loginFilter" />
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<security:logout invalidate-session="true" logout-url="/logout"
success-handler-ref="customLogoutSuccessHandler" delete-cookies="JSESSIONID" />
<security:headers>
<security:frame-options disabled="true"/>
security:headers>
<security:csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
<security:anonymous enabled="false"/>
<security:custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
<security:custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER" />
<security:session-management
session-authentication-strategy-ref="sas"
invalid-session-url="/loginController/loginFail" />
security:http>
<bean id="customLogoutSuccessHandler" class="com.zhiyun.front.common.interceptor.CustomLogoutSuccessHandler"/>
<bean id="csrfSecurityRequestMatcher" class="com.zhiyun.front.common.interceptor.CsrfSecurityRequestMatcher"/>
<bean id="accessDeniedHandler" class="com.zhiyun.front.common.interceptor.CustomAccessDeniedHandler"/>
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg name="loginFormUrl" value="/login.html" />
bean>
<bean id="customAuthenticationEntryPoint" class="com.zhiyun.front.common.interceptor.CustomAuthenticationEntryPoint"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myAuthenticationProvider">
security:authentication-provider>
security:authentication-manager>
<bean id="loginFilter" class="com.zhiyun.front.common.interceptor.CustomAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler"/>
<property name="authenticationFailureHandler" ref="authenticationFailureHandler"/>
<property name="filterProcessesUrl" value="/login"/>
<property name="usernameParameter" value="username"/>
<property name="passwordParameter" value="password"/>
<property name="sessionAuthenticationStrategy" ref="sas" />
bean>
<bean id="authenticationFailureHandler" class="com.zhiyun.front.common.interceptor.CustomAuthenticationFailureHandler"/>
<bean id="authenticationSuccessHandler" class="com.zhiyun.front.common.interceptor.CustomAuthenticationSuccessHandler"/>
<bean id="myFilter"
class="com.zhiyun.front.common.interceptor.AccessSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="myAccessDecisionManagerBean" />
<property name="accessSecurityMetadataSource" ref="securityMetadataSource" />
bean>
<bean id="myAccessDecisionManagerBean"
class="com.zhiyun.front.common.interceptor.AccessDecisionManagerImpl"/>
<bean id="securityMetadataSource" class="com.zhiyun.front.common.interceptor.AccessSecurityMetadataSource" >
<property name="permissionDao" ref="systemPermissionDao"/>
<property name="roleDao" ref="systemRoleDao"/>
bean>
<bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<constructor-arg name="expiredUrl" value="/loginController/loginFail" />
bean>
<bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg ref="sessionRegistry"/>
<property name="maximumSessions" value="5" />
<property name="exceptionIfMaximumExceeded" value="false" />
bean>
<bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
bean>
<bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg ref="sessionRegistry"/>
bean>
list>
constructor-arg>
bean>
<bean id="sessionRegistry"
class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
<constructor-arg name="sessionRepository" ref="sessionRepository"/>
bean>
beans>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>
classpath*:applicationContext.xml,
classpath*:spring-session.xml,
classpath*:spring-security.xml
param-value>
context-param>
<filter>
<filter-name>springSessionRepositoryFilterfilter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilterfilter-name>
<url-pattern>/*url-pattern>
<dispatcher>REQUESTdispatcher>
<dispatcher>ERRORdispatcher>
filter-mapping>
之所以要修改该配置,是因为在整合过程中,虽然spring-session已经生效,但是在访问spring-security登陆接口时,会出现session不一致的情况,spring-security过滤器中使用的是原始的session,然而在登录完成后,后续接口调用中,使用的是spring-session包装过后的session,这就导致了,登陆接口与其他业务接口session不一致的问题,因此,我在这里重写了DelegatingFilterProxy类: SecurityDelegatingFilterProxy
<filter>
<filter-name>springSecurityFilterChainfilter-name>
<filter-class>com.zhiyun.front.common.interceptor.SecurityDelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSecurityFilterChainfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
SecurityDelegatingFilterProxy.java代码
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SecurityDelegatingFilterProxy extends DelegatingFilterProxy {
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.filter.DelegatingFilterProxy#invokeDelegate(javax
* .servlet.Filter, javax.servlet.ServletRequest,
* javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
protected void invokeDelegate(Filter delegate, ServletRequest request,
ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request instanceof HttpServletRequest
&& response instanceof HttpServletResponse) {
HttpServletRequest contextHolderRequest = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
//request对象是原始的session对象,contextHolderRequest是spring-session封装后的session
//此处进行对比,如果不相同,则将原始的替换成spring-session封装后的
if (request != contextHolderRequest) {
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(
(HttpServletRequest) request,
(HttpServletResponse) response), true);
}
}
super.invokeDelegate(delegate, request, response, filterChain);
}
}
在没有到达springmvc的DispatcherServlet前,RequestContextHolder中都是原始的HttpServletRequest,而自定义的security的filter是在DispatcherServlet之前执行的,所以filter获得的request是原始的。web.xml中security的filter自己来实现,在super.invokeDelegate之前先判断RequestContextHolder的request是不是包装后的session,不是的话自己set进去.
附上完整的web.xml配置
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>
classpath*:applicationContext.xml,
classpath*:spring-session.xml,
classpath*:spring-security.xml
param-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListenerlistener-class>
listener>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
<async-supported>trueasync-supported>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>springSessionRepositoryFilterfilter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilterfilter-name>
<url-pattern>/*url-pattern>
<dispatcher>REQUESTdispatcher>
<dispatcher>ERRORdispatcher>
filter-mapping>
<filter>
<filter-name>characterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>characterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>springSecurityFilterChainfilter-name>
<filter-class>com.zhiyun.front.common.interceptor.SecurityDelegatingFilterProxyfilter-class>
filter>
<filter-mapping>
<filter-name>springSecurityFilterChainfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisherlistener-class>
listener>
web-app>
至此spring-security与spring*session整合完毕
感谢大神的解答:
[1]: https://www.oschina.net/question/1245392_2276925