春季安全并发会话不起作用
Posted
技术标签:
【中文标题】春季安全并发会话不起作用【英文标题】:spring security concurrent session not working 【发布时间】:2016-11-06 05:18:24 【问题描述】:我正在使用 Spring 4 和 Hibernate 4 我已经实现了 Spring 安全性并且它工作正常,但是我不想允许使用相同的凭据进行并发登录。 1.我在web.xml中添加了监听器“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>
spring-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;
【问题讨论】:
password.equalsIgnoreCase(user.getPassword()) 从安全的角度来看可能不是一个好主意。您如何进行测试并得出结论它不起作用? (例如,同一浏览器中的多个选项卡通常对给定站点使用相同的会话)。 不...我使用了不同的浏览器,还尝试以隐身模式打开链接,但它允许我使用相同的凭据登录。我们应该使用什么来比较密码以获得更好的安全性? 对于密码,不要忽略大小写。 【参考方案1】:看看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 分钟内访问该网站)。
【讨论】:
我已经浏览了 spring 安全参考文档,并且仅在此文档的帮助下实现了此并发控制,并且我尝试了上述error-if-maximum-exceeded="true"
但它没有工作。以上是关于春季安全并发会话不起作用的主要内容,如果未能解决你的问题,请参考以下文章