`

使用session监听+spring MVC拦截器禁止用户重复登录

 
阅读更多
http://blog.csdn.net/jrn1012/article/details/25781319
在许多web项目中,需要禁止用户重复登录。一般来说有两种做法:

         一是在用户表中维护一个字段isOnLine(是否在线),用户登录时,设定值为true,用户退出时设定为false,在重复登录时,检索到该字段为true时,禁止用户登录。这种方法有明显的漏洞,及用户在非正常情况退出(关闭浏览器、关机等)是,该字段值一直为true,会导致用户无法登录。

          而另一种比较通用的做法是使用session监听,重复登录后,强制之前登录的session过期,从而踢出了该用户。具体做法是:使用监听器维护服务器上缓存的sessionMap,该map是以<session.getId(),session>的键值对,在登录后,使用userid替换session.getId(),从而使得sessionMap中维护的是<userid, session>的键值对。后续该帐号重复登录时,检索到已有该帐号session则强制它过期。

  
1、web.xml中配置session监听
<listener>  
        <listener-class>com.cnpc.framework.listener.SessionListener</listener-class>          
</listener>  


2、session监听SessionListener类
package com.cnpc.framework.listener;  
  
import javax.servlet.http.HttpSessionEvent;  
import javax.servlet.http.HttpSessionListener;  
  
import com.cnpc.framework.utils.SessionContext;  
  
public class SessionListener implements HttpSessionListener {  
    public  static SessionContext sessionContext=SessionContext.getInstance();  
   
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {  
        sessionContext.AddSession(httpSessionEvent.getSession());  
    }  
  
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {  
        sessionContext.DelSession(httpSessionEvent.getSession());  
    }  
}  

SessionContex类(使用单例模式)
package com.cnpc.framework.utils;  
  
import java.util.HashMap;  
  
import javax.servlet.http.HttpSession;  
  
  
public class SessionContext {  
    private static SessionContext instance;  
    private HashMap<String,HttpSession> sessionMap;  
   
    private SessionContext() {  
        sessionMap = new HashMap<String,HttpSession>();  
    }  
  
    public static SessionContext getInstance() {  
        if (instance == null) {  
            instance = new SessionContext();  
        }  
        return instance;  
    }  
  
    public synchronized void AddSession(HttpSession session) {  
        if (session != null) {  
            sessionMap.put(session.getId(), session);  
        }  
    }  
  
    public synchronized void DelSession(HttpSession session) {  
        if (session != null) {  
            sessionMap.remove(session.getId());  
            if(session.getAttribute("userid")!=null){  
                sessionMap.remove(session.getAttribute("userid").toString());  
                //session.invalidate();   
            }  
        }  
    }  
  
    public synchronized HttpSession getSession(String session_id) {  
        if (session_id == null) return null;  
        return (HttpSession) sessionMap.get(session_id);  
    }  
  
    public HashMap getSessionMap() {  
        return sessionMap;  
    }  
  
    public void setMymap(HashMap sessionMap) {  
        this.sessionMap = sessionMap;  
    }  
  
}  

3、用户登录成功后,更新session Map,如重复登录,强制之前session过期
public void sessionHandlerByCacheMap(HttpSession session){  
        String userid=session.getAttribute("userid").toString();  
        if(SessionListener.sessionContext.getSessionMap().get(userid)!=null){  
            HttpSession userSession=(HttpSession)SessionListener.sessionContext.getSessionMap().get(userid);  
            //注销在线用户  
            userSession.invalidate();             
            SessionListener.sessionContext.getSessionMap().remove(userid);  
            //清除在线用户后,更新map,替换map sessionid  
            SessionListener.sessionContext.getSessionMap().remove(session.getId());   
            SessionListener.sessionContext.getSessionMap().put(userid,session);   
        }  
        else  
        {  
            // 根据当前sessionid 取session对象。 更新map key=用户名 value=session对象 删除map  
                SessionListener.sessionContext.getSessionMap().get(session.getId());  
            SessionListener.sessionContext.getSessionMap().put(userid,SessionListener.sessionContext.getSessionMap().get(session.getId()));  
            SessionListener.sessionContext.getSessionMap().remove(session.getId());  
        }  
    } 


4、spring MVC拦截器校验session是否过期,如果过期,给出提示,并跳转到登录界面。
    拦截器配置  
      <init-param>  
            <description>Spring MVC配置文件</description>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>classpath:controller.xml</param-value>  
        </init-param>  
controller.xml配置
[html] view plaincopy在CODE上查看代码片派生到我的代码片
<mvc:interceptors>     
        <bean class="com.cnpc.framework.interceptor.AuthInterceptor" />    
    </mvc:interceptors>  
 

拦截器authInterceptor
package com.cnpc.framework.interceptor;  
  
import java.io.PrintWriter;  
import java.util.Map;  
  
import javax.annotation.Resource;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
  
import org.springframework.stereotype.Component;  
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  
  
import com.cnpc.framework.common.SessionContainer;  
  
@Component("SpringMVCInterceptor")  
public class AuthInterceptor extends HandlerInterceptorAdapter {      
      
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
        request.setCharacterEncoding("UTF-8");  
        response.setCharacterEncoding("UTF-8");   
        response.setContentType("text/html;charset=UTF-8");  
   
        //过滤登录、退出访问  
        String[] noFilters = new String[] { "/auth/login", "/auth/logout" };  
        String uri = request.getRequestURI();  
  
        boolean beFilter = true;  
        for (String s : noFilters) {  
            if (uri.indexOf(s) != -1) {  
                beFilter = false;  
                break;  
            }  
        }  
        SessionContainer sessionContainer = (SessionContainer) request.getSession().getAttribute("SessionContainer");  
        if (beFilter) {  
            if (null == sessionContainer) {  
                //ajax方式交互  
                if (request.getHeader("x-requested-with") != null  
                        && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest"))// 如果是ajax请求响应头会有,x-requested-with;  
                {                     
                    response.setHeader("sessionstatus", "timeout");// 在响应头设置session状态  
                    return false;  
                }  
                // 未登录  
                PrintWriter out = response.getWriter();  
                StringBuilder builder = new StringBuilder();  
                builder.append("<script type=\"text/javascript\" charset=\"UTF-8\">");  
                builder.append("alert(\"页面过期,请重新登录\");");  
                builder.append("window.top.location.href='/auth/logout';");  
                builder.append("</script>");  
                out.print(builder.toString());  
                out.close();  
                return false;  
            } else {                      
                // 添加系统日志  
                // -----------------------------------  
                // -----------------------------------  
            }  
        }  
        Map paramsMap = request.getParameterMap();  
        return super.preHandle(request, response, handler);  
    }  
}  

以上Sprring MVC拦截器在同服务器以ajax方式交互时,前台需做如下相应处理:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
//控制ajax请求,session超时处理页面跳转  
 $.ajaxSetup({     
       contentType:"application/x-www-form-urlencoded;charset=utf-8",     
       complete:function(XMLHttpRequest,textStatus){     
             var sessionstatus=XMLHttpRequest.getResponseHeader("sessionstatus"); // 通过XMLHttpRequest取得响应头,sessionstatus,  
               if(sessionstatus=="timeout"){     
                     // 如果超时就处理 ,指定要跳转的页面     
                     alert("页面过期,请重新登录");   
                     window.top.location.href="/auth/logout";  
                    }    
                  }       
               }   
          );  
  

           以上方式完成了禁止用户重复登录的功能,并将踢出之前登录的帐号,这在不同的浏览器中使用没有问题。但是因为在同一个浏览器中,多个标签页(Tab页)是共享session的,在同一个浏览器中并不会创建一个新的session。所以同一个浏览器还是可以重复登录的,目前还没有什么很好解决办法。本来想如果重复登录,则通过校验session是否存在来禁止登录。但是之前登录的若关闭了标签页,则在这个浏览器上的其他标签页则再也无法登录了。所以这个做法也有问题。
分享到:
评论

相关推荐

    详解Spring MVC拦截器实现session控制

    主要介绍了详解Spring MVC拦截器实现session控制,使用session监听,重复登录后,强制之前登录的session过期。有兴趣的可以了解一下。

    SpringMVC拦截器实现监听session是否过期详解

    主要介绍了SpringMVC拦截器实现监听session是否过期详解,还是比较不错的,这里分享给大家,供需要的朋友参考。

    拦截器和控制器的区别

    4、拦截器可以利用依赖注入,因此在spring框架程序中,优先拦截器 5、拦截器是包裹在过滤器中使用的。 复习 converter 转换器 i18n struts2 spring MVC 拦截器 interceptor 过滤器 filter web.xml ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.5.3.1. RedirectView 13.5.3.2. redirect:前缀 13.5.3.3. forward:...

    springboot学习思维笔记.xmind

    拦截器配置 @ControllerAdivce @ExceptionHandler @InitBinder @ModelAttribute 其他配置 ViewController 路径匹配参数配置 WebMvcConfigurerAdapter WebMvcConfigurer ...

    Spring中文帮助文档

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

    Spring API

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

    Spring 2.0 开发参考手册

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2....

    spring chm文档

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2....

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

    8.8 拦截器 332 8.9 依赖注入 335 8.9.1 EJB注入 336 8.9.2 资源注入 339 8.10 配置EJB引用 340 8.11 使用计时器进行任务调度 342 8.12 本章小结 345 第9章 消息驱动EJB 346 9.1 JMS和EJB 347 9.1.1 为什么使用MDB ...

    从J2SE到J2EE知识点介绍

    1. struts2的拦截器定义以及使用 153 2. struts标签 160 3. Struts 2 标签库说明及使用 160 4. set 描述 169 5. text 描述 170 6. property 描述 170 7. Struts的异常处理 171 8. Struts的上传与下载 178 五、 ...

    Java学习笔记-个人整理的

    {12.2}登录数据库}{151}{section.12.2} {12.3}创建表格}{152}{section.12.3} {12.4}关于null值}{154}{section.12.4} {12.5}操作符与实例}{154}{section.12.5} {12.5.1}where}{154}{subsection.12.5.1} {12.6}...

Global site tag (gtag.js) - Google Analytics