继续说说spring security之并发控制(Concurrency Control)

定义,作用,说明:

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

 

posted @ 2014-10-21 12:11  时游  阅读(7644)  评论(1编辑  收藏  举报