无法使 Spring 3 会话并发控制工作

Posted

技术标签:

【中文标题】无法使 Spring 3 会话并发控制工作【英文标题】:Unable to make Spring 3 Session Concurency Control work 【发布时间】:2011-04-25 01:53:53 【问题描述】:

使用 Spring Security 3.1.0,我似乎无法让并发会话控制功能工作。当我使用 IE 和 FireFox(使用我的本地工作站)同时登录我的系统时,我在会话注册表中看到了我的用户原则两次。我希望并发会话控制将我注销或抛出异常或执行一些指示我多次登录该站点但不允许这样做的操作。

不管怎样,使用 HTTP 命名空间元素的自动配置,我根本无法让并发控制工作,即使指定我的站点使用自定义登录表单也是如此。我想知道这是否可能是因为我的身份验证是通过 LDAP 提供的......?

这是我的安全配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
 xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">

 <http auto-config="false" use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint">
     <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
     <custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter"/>
     <session-management session-authentication-strategy-ref="sas"/>
  <intercept-url pattern="/" access="permitAll" />
  <intercept-url pattern="/css/**" access="permitAll" />
  <intercept-url pattern="/images/**" access="permitAll" />
  <intercept-url pattern="/js/**" access="permitAll" />
  <intercept-url pattern="/public/**" access="permitAll" />
  <intercept-url pattern="/home/**" access="permitAll" />
  <intercept-url pattern="/admin/user/**" access="hasRole('AUTH_MANAGE_USERS')" />
  <intercept-url pattern="/admin/group/**" access="hasRole('AUTH_MANAGE_USERS')" />
  <intercept-url pattern="/**" access="isAuthenticated()" />
  <access-denied-handler error-page="/403.html"/>
  <logout invalidate-session="true" logout-success-url="/public/home.do"/>
 </http>

    <beans:bean id="authenticationProcessingFilterEntryPoint"
          class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
        <beans:property name="loginFormUrl" value="/public/login.do"/>
        <beans:property name="forceHttps" value="false"/>
    </beans:bean>

  <beans:bean id="concurrencyFilter"
       class="org.springframework.security.web.session.ConcurrentSessionFilter">
     <beans:property name="sessionRegistry" ref="sessionRegistry" />
     <beans:property name="expiredUrl" value="/expired.html" />
   </beans:bean>

   <beans:bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
     <beans:property name="sessionAuthenticationStrategy" ref="sas" />
     <beans:property name="authenticationManager" ref="authenticationManager" />
   </beans:bean>

   <beans:bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
     <beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
     <beans:property name="maximumSessions" value="1" />
     <beans:property name="exceptionIfMaximumExceeded" value="true"/>
   </beans:bean>

 <authentication-manager alias="authenticationManager">
  <authentication-provider ref='ldapProvider' />
  <authentication-provider ref="externalUserLdapProvider"/>
 </authentication-manager>

 <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />

 <beans:bean id="securityContext" 
  class="org.springframework.security.core.context.SecurityContextHolder" factory-method="getContext"/>

 <beans:bean id="ldapProvider"
  class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
  <beans:constructor-arg ref="bindAuthenticator" />
  <beans:constructor-arg ref="userService" />
  <beans:property name="userDetailsContextMapper" ref="permissionedUserContextMapper" />
 </beans:bean>

 <beans:bean id="permissionedUserContextMapper"
  class="...service.impl.PermissionedUserContextMapperImpl" >
  <beans:property name="userDao" ref="userDao"/>
 </beans:bean>  

 <!-- LDAP via AD-->
 <beans:bean id="bindAuthenticator"
  class="org.springframework.security.ldap.authentication.BindAuthenticator">
  <beans:constructor-arg ref="contextSource" />
  <beans:property name="userSearch" ref="userSearch" />
 </beans:bean>

 <beans:bean id="userSearch"
  class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
  <beans:constructor-arg>
   <beans:value></beans:value>
  </beans:constructor-arg>
  <beans:constructor-arg>
   <beans:value>(sAMAccountName=0)</beans:value>
  </beans:constructor-arg>
  <beans:constructor-arg ref="contextSource" />
  <beans:property name="searchSubtree">
   <beans:value>true</beans:value>
  </beans:property>
 </beans:bean>

 <beans:bean id="contextSource"
  class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  <beans:constructor-arg
   value="ldap://omitted" />
  <beans:property name="userDn"
   value="ommitted" />
  <beans:property name="password" value="omitted" />
 </beans:bean>

 <!--  Second LDAP Authenticator (Apache DS) -->
    <beans:bean id="externalUserLdapProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
        <beans:constructor-arg ref="externalUserBindAuthenticator"/>
  <beans:constructor-arg ref="userService" />
  <beans:property name="userDetailsContextMapper" ref="permissionedUserContextMapper" />
    </beans:bean>

 <beans:bean id="externalUserBindAuthenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator">
  <beans:constructor-arg ref="externalUserContextSource" />
  <beans:property name="userDnPatterns">
   <beans:list>
    <beans:value>cn=0,ou=Users</beans:value>
   </beans:list>
  </beans:property>
 </beans:bean>

 <beans:bean id="externalUserContextSource" 
   class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
     <beans:constructor-arg value="ldap://omitted"/>
 </beans:bean>

</beans:beans>

如果用户记录超过 1 个会话,我是否缺少一些应该告诉并发控制策略 barf 的属性?我知道同一个用户正在记录多个会话——因为我在会话注册表中看到了重复的原则。

非常感谢任何/所有回复!提前致谢!

【问题讨论】:

【参考方案1】:

SessionRegistry 使用equals()/hashCode()UserDetails 来查找同一用户的会话。如果你有自定义UserDetails,可能没有实现。

【讨论】:

这绝对是问题所在。把我的骨头。非常感谢!

以上是关于无法使 Spring 3 会话并发控制工作的主要内容,如果未能解决你的问题,请参考以下文章

春季安全并发会话不起作用

Shiro 中的并发会话控制

无法从 Azure 服务总线中的并发会话按顺序接收消息

具有并发会话的 grails 3

SpringSecurity - 学习笔记 - 会话管理之并发控制:同一账号只允许在一个设备登录

SpringSecurity - 学习笔记 - 会话管理之并发控制:同一账号只允许在一个设备登录