SpringSecurity3.1.2控制一个账户同时只能登录一次

网上看了很多资料,发现多多少少都有一些不足(至少我在使用的时候没成功),后来经过探索研究,得到解决方案。

 

具体SpringSecurity3怎么配置参考SpringSecurity3.1实践,这里只讲如何配置可以控制一个账户同时只能登录一次的配置实现。

 

网上很多配置是这样的,在标签中加入concurrency-control配置,设置max-sessions=1。

Xml代码   收藏代码
  1. <session-management invalid-session-url="/timeout">  
  2.   <concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>  
  3. session-management>  

 但是经测试一直没成功,经过一番查询原来是UsernamePasswordAuthenticationFilter中的一个默认属性sessionStrategy导致的。

首先我们在spring-security.xml中添加,可以看到经过的过滤器如下:

Java代码   收藏代码
  1. Security filter chain: [  
  2.   ConcurrentSessionFilter --- (主要)并发控制过滤器,当配置时,会自动注册  
  3.   SecurityContextPersistenceFilter  --- 主要是持久化SecurityContext实例,也就是SpringSecurity的上下文。也就是SecurityContextHolder.getContext()这个东西,可以得到Authentication。  
  4.   LogoutFilter   ---  注销过滤器  
  5.   PmcUsernamePasswordAuthenticationFilter  --- (主要)登录过滤器,也就是配置文件中的配置、(本文主要问题就在这里)  
  6.   RequestCacheAwareFilter                 ---- 主要作用为:用户登录成功后,恢复被打断的请求(这些请求是保存在Cache中的)。这里被打断的请求只有出现AuthenticationException、AccessDeniedException两类异常时的请求。  
  7.   SecurityContextHolderAwareRequestFilter  ---- 不太了解  
  8.   AnonymousAuthenticationFilter        ------  匿名登录过滤器  
  9.   SessionManagementFilter              ----  session管理过滤器  
  10.   ExceptionTranslationFilter         ---- 异常处理过滤器(该过滤器只过滤下面俩拦截器)[处理的异常都是继承RuntimeException,并且它只处理AuthenticationException(认证异常)和AccessDeniedException(访问拒绝异常)]  
  11.   PmcFilterSecurityInterceptor       ------  自定义拦截器  
  12.   FilterSecurityInterceptor  
  13. ]  

 那么先来看UsernamePasswordAuthenticationFilter,它实际是执行其父类AbstractAuthenticationProcessingFilter的doFilter()方法,看部分源码:

Java代码   收藏代码
  1. try {  
  2.         //子类继承该方法进行认证后返回Authentication  
  3.             authResult = attemptAuthentication(request, response);  
  4.             if (authResult == null) {  
  5.                 // return immediately as subclass has indicated that it hasn't completed authentication  
  6.                 return;  
  7.             }  
  8.         //判断session是否过期、把当前用户放入session(这句是关键)  
  9.             sessionStrategy.onAuthentication(authResult, request, response);  
  10.         } catch(InternalAuthenticationServiceException failed) {  
  11.             logger.error("An internal error occurred while trying to authenticate the user.", failed);  
  12.             unsuccessfulAuthentication(request, response, failed);  
  13.             return;  
  14.         }  

 看sessionStrategy的默认值是什么?

Java代码   收藏代码
  1. private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();  

 然后我们查询NullAuthenticatedSessionStrategy类的onAuthentication()方法竟然为空方法[问题就出现在这里]。那么为了解决这个问题,我们需要向UsernamePasswordAuthenticationFilter中注入类ConcurrentSessionControlStrategy。

这里需要说明下,注入的属性name名称为sessionAuthenticationStrategy,因为它的setter方法这么写的:

Java代码   收藏代码
  1. public void setSessionAuthenticationStrategy(SessionAuthenticationStrategy sessionStrategy) {  
  2.    this.sessionStrategy = sessionStrategy;  
  3. }  

 这样,我们的配置文件需要这样配置(只贴出部分代码)[具体参考SpringSecurity3.1实践那篇博客]:

Xml代码   收藏代码
  1. <http entry-point-ref="loginAuthenticationEntryPoint">  
  2.     <logout   
  3. delete-cookies="JSESSIONID"  
  4.         logout-success-url="/"   
  5.         invalidate-session="true"/>  
  6.   
  7. lt;access-denied-handler error-page="/common/view/accessDenied.jsp"/>  
  8.   
  9.     <session-management invalid-session-url="/timeout" session-authentication-strategy-ref="sas"/>  
  10.       
  11.     <custom-filter ref="pmcLoginFilter" position="FORM_LOGIN_FILTER"/>  
  12.     <custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER"/>  
  13.     <custom-filter ref="pmcSecurityFilter" before="FILTER_SECURITY_INTERCEPTOR"/>  
  14. http>  
  15.   
  16.   
  17.   
  18. <beans:bean id="pmcLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">  
  19.     <beans:property name="authenticationManager" ref="authManager">beans:property>  
  20.     <beans:property name="authenticationFailureHandler" ref="failureHandler">beans:property>  
  21.     <beans:property name="authenticationSuccessHandler" ref="successHandler">beans:property>  
  22.     <beans:property name="sessionAuthenticationStrategy" ref="sas">beans:property>  
  23. beans:bean>  
  24.   
  25.   
  26. <beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">  
  27.     <beans:property name="expiredUrl" value="/timeout">beans:property>  
  28.     <beans:property name="sessionRegistry" ref="sessionRegistry">beans:property>  
  29. beans:bean>  
  30.   
  31. t;!-- 未验证用户的登录入口 -->  
  32. <beans:bean id="loginAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  
  33.     <beans:constructor-arg name="loginFormUrl" value="/">beans:constructor-arg>  
  34. beans:bean>  
  35.   

你可能感兴趣的:(spring,security)