spring-security整合spring-session

spring-security整合spring-session

  • 引入依赖
    • 增加spring-session.xml配置文件
    • 在原有的spring-security.xml内容基础上,修改配置信息
    • 完整的spring-security.xml配置如下
    • web.xml配置文件中增加如下配置,使spring-session生效
    • 修改web.xml中spring-security过滤器配置

引入依赖

    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session</artifactId>
      <version>1.3.3.RELEASE</version>
    </dependency>

增加spring-session.xml配置文件


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

在原有的spring-security.xml内容基础上,修改配置信息

	<bean id="sessionRegistry"
		  class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
		<constructor-arg name="sessionRepository" ref="sessionRepository"/>
	bean>

完整的spring-security.xml配置如下


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

web.xml配置文件中增加如下配置,使spring-session生效

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

修改web.xml中spring-security过滤器配置

之所以要修改该配置,是因为在整合过程中,虽然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

你可能感兴趣的:(JAVA)