定義,作用,說明:
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的自問自答,這種精神很想點贊,可惜要登錄,要登錄就是要翻牆,可惜點了半天還沒有出來。欲跋千山,涉萬水,翻過高牆,穿過荒原,只為跟你說聲:謝謝。
http://stackoverflow.com/questions/26041756/concurrency-control-is-not-working