spring security并发会话无法正常工作

时间:2016-07-04 12:54:36

标签: spring spring-mvc spring-security

我正在使用Spring 4和Hibernate 4我实现了Spring安全性并且工作正常但是,我不想允许使用相同凭据的并发登录。 1.我已将Listener“HttpSessionEventPublisher”添加到web.xml,并在spring security中使用“Session management”标记来实现并发控制,但它不起作用以下是完整的代码:

的web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<listener>
    <listener-class>
        org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern> 
</filter-mapping>

弹簧security.xml文件

<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.xsd    
                    http://www.springframework.org/schema/security
                    http://www.springframework.org/schema/security/spring-security.xsd">


<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/login" access="permitAll()" />
    <intercept-url pattern="/loginError" access="isAnonymous()" />
    <intercept-url pattern="/sessionTimeout" access="isAnonymous()" />
    <intercept-url pattern="/forgotPassword" access="isAnonymous()" />
    <intercept-url pattern="/requestNewPassword" access="isAnonymous()" />
    <intercept-url pattern="/assets/**" access="permitAll()" />

    <intercept-url pattern="/sessionExpired" access="isAnonymous()" />
    <intercept-url pattern="/error" access="isAnonymous()" />


    <form-login  login-page="/login"
                 username-parameter="userId"
                 password-parameter="password"
                 authentication-success-handler-ref="cdatSuccessHandler"
                 authentication-failure-url="/loginError" />

    <!-- <session-management session-fixation-protection="newSession" invalid-session-url="/sessionTimeout">
    </session-management> -->

    <session-management>
        <concurrency-control max-sessions="1" expired-url="/sessionTimeout" />
    </session-management>

    <intercept-url pattern="/**" access="isAuthenticated()"/>

    <csrf/>

    <!-- <access-denied-handler error-page="/sessionExpired"/>  -->

    <headers>
        <xss-protection enabled="true" block="true"/>
    </headers>

</http>

<authentication-manager erase-credentials="true">
    <authentication-provider ref="cdatAuthenticationProvider"> </authentication-provider>
</authentication-manager>

身份验证提供程序类

package com.component.cdat.security.configuration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import     org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import com.component.cdat.project.bean.MappProjectUser;
import com.component.cdat.user.bean.User;
import com.component.cdat.user.services.UserService;

@Component("cdatAuthenticationProvider")
public class CDATAuthenticationProvider implements AuthenticationProvider{

@Autowired
UserService userService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    String loginId = authentication.getName().trim();
    String password = (String) authentication.getCredentials();

    if(loginId == null || password == null || loginId.isEmpty() || password.isEmpty()){
        // throw exception
        System.out.println("username or password is empty!!");
        throw new NullPointerException();
    }

    User user = userService.getUserByUserName(loginId);

    if(user == null || !loginId.equalsIgnoreCase(user.getUserName())){
        System.out.println("User Not Found!!");
        throw new NullPointerException();
    }

    if(!password.equalsIgnoreCase(user.getPassword())){
        System.out.println("Pasword is incorrect!!");
        throw new NullPointerException();
    }

    Collection<? extends GrantedAuthority> authorities = getAuthorities(user);

    return new UsernamePasswordAuthenticationToken(user, password, authorities);
}

private Collection<? extends GrantedAuthority> getAuthorities(User user){

    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    List<MappProjectUser> userAuthorityList = userService.getUserRole(user.getUserId());

    for(MappProjectUser userAuthority : userAuthorityList){
        authorities.add(new SimpleGrantedAuthority("ROLE_" + userAuthority.getUserType().getShortDesc()));
    }
    return authorities;
}

@Override
public boolean supports(Class<?> arg0) {
    return true;
}
}

1 个答案:

答案 0 :(得分:0)

查看reference documentation(这是针对spring security 3.1):

  <http>
      ...
      <session-management>
          <concurrency-control max-sessions="1" />
      </session-management>
  </http>
  

这会阻止用户多次登录 - 第二次登录会导致第一次登录失效。通常您更愿意阻止第二次登录,在这种情况下您可以使用

<http>
    ...
    <session-management>
        <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
    </session-management>
</http>

尝试将error-if-maximum-exceeded="true"添加到concurrency-control标记,看看它是否有效。请注意这种并发控制的缺点:如果用户在没有注销的情况下关闭浏览器,他将无法在会话超时之前登录(通常是30分钟......所以他赢了但不能在接下来的30分钟内访问该网站。)