定义,作用,说明:
Concurrency Control:并发控制,主要用于避免同一用户多次登录,重复登录以及包括相关的session管理--具体官网---》
先看官网:http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#session-mgmt
官网的并发控制已经说得比较清楚,但是偏偏有人(例如我)重写了(自定义了)验证的方法,导致了失效的问题,至此,一起说说spring security之并发控制配置以及相关编写:
分为三种方式:
基本配置:
web.xml 加入监听
<listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener>
第一种,入门试(简单配置)没有自定义了spring security验证的
<http> ... <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> </session-management> </http>
或者
<http> ... <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> </session-management> </http>
区别在于前者剔除上一个用户,后者第二个不给登录
记住前提:没有自定义验证方法,官网:
If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly. More details can be found in the Session Management chapter.
但如果自定义了自定义的UserDetails 则需要重定义equal和hashcode
第二种方法:
打开官网其实已经说得很清楚了。。。。
还不清楚再看来自iteye的网友 http://sb33060418.iteye.com/blog/1953515
第三种方法(我就是用这种。。。)
首先看看我的验证(使用程序的方法去调用,很大限度的自定义了验证)
public LoginInfo login(@RequestParam(defaultValue="") String username,@RequestParam(defaultValue="") String password,HttpServletRequest request,HttpServletResponse response){ if(!checkValidateCode(request)){ return new LoginInfo().failed().msg("验证码错误!"); } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); /* DetachedCriteria detachedCriteria = DetachedCriteria.forClass(CwSysUser.class,"cwSysUser"); detachedCriteria.add(Restrictions.eq("userNo", username)); if(cwSysUserService.countUser(detachedCriteria)==0){ return new LoginInfo().failed().msg("用户名: "+username+" 不存在."); } */ try { Authentication authentication = myAuthenticationManager.authenticate(authRequest); //调用loadUserByUsername SecurityContextHolder.getContext().setAuthentication(authentication); HttpSession session = request.getSession(); session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext()); // 这个非常重要,否则验证后将无法登陆 sas.onAuthentication(authentication, request, response); return new LoginInfo().success().msg(authentication.getName()); }catch (AuthenticationException ex) { if(ex.getMessage()==null){ return new LoginInfo().failed().msg("用户名不存在."); } return new LoginInfo().failed().msg("用户名或密码错误"); } }
说明:
Authentication authentication = myAuthenticationManager.authenticate(authRequest); //这里就是在程序中用
myAuthenticationManager调用了验证信息,基于myAuthenticationManager在下面xml的配置重新写了loadUserByUsername方法
sas.onAuthentication(authentication, request, response);// 这里就是手动调用了并发控制(在xml做了注入配置)
配置spring-security.xml (配置基本和二差不错,但是少了自定义登录拦截配置)
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" /> <session-management session-authentication-strategy-ref="sas" /> </http> <beans:bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter"> <beans:property name="sessionRegistry" ref="sessionRegistry" /> <beans:property name="expiredUrl" value="/session-expired.htm" /> </beans:bean> <beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy"> <beans:constructor-arg> <beans:list> <beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy"> <beans:constructor-arg ref="sessionRegistry" /> <beans:property name="maximumSessions" value="1" /> </beans:bean> <beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"> </beans:bean> <beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy"> <beans:constructor-arg ref="sessionRegistry" /> </beans:bean> </beans:list> </beans:constructor-arg> </beans:bean> <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" /> <authentication-manager alias="myAuthenticationManager"> <authentication-provider user-service-ref="cwSysUserDetailsService"> <!-- 数据库提供者 --> <password-encoder hash="md5"></password-encoder> </authentication-provider> </authentication-manager>
至此,完成。。。。。
非常感谢:stackoverflow和ma4的自问自答,这种精神很想点赞,可惜要登录,要登录就是要FQ,可惜点了半天还没有出来。欲跋千山,涉万水,翻过高墙,穿过荒原,只为跟你说声:谢谢。
http://stackoverflow.com/questions/26041756/concurrency-control-is-not-working