2016-07-04 56 views
0

我正在使用Spring 4和Hibernate 4我已經實現了Spring安全性及其工作正常,但是,我不想允許使用相同憑據的併發登錄。 1.我已經在web.xml中添加了Listener「HttpSessionEventPublisher」,並且在spring security中使用了「會話管理」標籤來實現併發控制,但它不起作用以下是完整的代碼:春季安全併發會話不工作

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; 
} 
} 
+0

從安全的角度來看,password.equalsIgnoreCase(user.getPassword())可能不是一個好主意。你如何測試並得出結論,它不起作用? (例如,同一瀏覽器內的多個選項卡通常對給定站點使用相同的會話)。 – Thierry

+0

不......我使用了不同的瀏覽器,並試圖在隱身模式下打開鏈接,但它允許我使用相同的憑據登錄。我們應該使用什麼來比較密碼以獲得更好的安全性? – susmit

+0

對於密碼,請不要忽略該情況。 – Thierry

回答

0

看看在reference documentation(這是春季安全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分鐘)。

+0

我已經瀏覽了spring安全參考文檔,並且僅在本文檔的幫助下實現了這個併發控制,並且我嘗試了上面的'error-if-maximum-exceeded =「true」'但它不起作用。 – susmit