zoukankan      html  css  js  c++  java
  • 同一账号同一时间在不同地点登陆实现登陆剔出功能

     公司项目中最近涉及到在网站登陆账号时,同一账号同一时间在不同地点登陆时要实现踢出功能,通俗的讲也就是用户的账号若已经登陆,那么此时此用户再在别的地方登陆就要将先前登陆的账号踢下线。

            先理一下思路,我们知道在客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是session。session在用户第一次访问服务器的时候自动创建,也就是说每个用户对应一个session。那么我们只要使先前登陆的用户失效就能实现踢出功能。

            方案实现,在登陆逻辑处添加一个方法,在方法中我们实现相应的同一账号登陆账号具备踢出下线功能。首先设定一个Map1,在里面我们以键值对的方式存储当前在线用户的用户ID和其对应的session,同时设定Map2,同样以键值对的方式存储被踢出用户的用户ID和其对应的session,另外为了防止java的垃圾回收机制将我们设定的Map回收,还要将两个Map存储到全局缓存application中。每当有用户登陆时会先判断是否有以此用户ID为Key的Map存在,若存在则说明用户已登陆,就将已登陆用户的用户ID和其对应的session存放到Map2中,并将已登陆用户对应的session注销,此时已登陆用户就会因session失效而掉线;若不存在则说明此用户没有在别处登陆。无论用户有没有在别处登陆,都将当前登陆的用户ID和其对应的session存入Map1中。这样就会实现用户登陆剔出功能。但这样还没有结束,我们将已登陆的用户剔出后,还要以弹框的形式提示他“当前用户已在别处登陆,请返回登陆页重新登陆”。弹框功能的实现是通过前台ajax监测后台登陆状态的形式实现的,ajax每隔一段时间向后台发送固定参数,以用户ID为唯一标识,检测登陆状态,若发现用户session已被放到踢出队列(即相应的Map中),则进行提示。另外,由于在JS中的函数是放在单独文件中实现的,所以无法实时获取对应的用户ID,在这里采用的是以cookie的形式将用户信息在登陆的html页面中存入,并在JS中获取并传入ajax的参数中。最后将正常登陆用户和被踢出的用户ID、登陆时间、登陆IP、登陆(或踢出状态)、sessionid都存入数据库中,以备出现问题可以进行查询。

    校验用户是否登陆代码:

    1. public void isLoaded(String sUser,HttpSession sessions,PageData pd) throws Exception{  
    2.         LoginDao dao=new LoginDao(pd);  
    3.         ServletContext application=pd.getSession().getServletContext();  
    4.           
    5.           
    6.         SimpleDateFormat mDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
    7.         String cTime=mDate.format(new Date());  
    8.         String IpAdrr=dao.getClientIp(pd);  
    9.         HashMap<String, HttpSession> cMap=(HashMap<String, HttpSession>) application.getAttribute(sUser);  
    10.   
    11.         try {  
    12.             //判断是否当前用户名已登录  
    13.             if(!(cMap==null)){  
    14.                 HttpSession mSession=cMap.get(sUser);  
    15.                 String mIP=fUserMap.get(sUser);  
    16.                 String mSessionId=mSession.getId();//被踢掉session  
    17.                 String cSessionId=sessions.getId();//在线session  
    18.                   
    19.                 //判断是否为同一浏览器登陆  
    20.                 if(!(mSessionId.equals(cSessionId))){                 
    21.                       
    22.                     passMap.put(sUser+"T", mSession);  
    23.                     application.setAttribute(sUser+"T", passMap);  
    24.                     dao.addLoginInfo(sUser, cTime, mIP, mSessionId, "用户在别处登陆");  
    25.                     if(!(mSession.getAttribute("ifNull")==null)){  
    26.                         mSession.invalidate();  
    27.                     }                 
    28.                 }  
    29.             }  
    30.               
    31.         } catch (Exception e) {  
    32.             log.debug("session已失效");  
    33.         }finally{  
    34.             //无论当前用户名登陆与否,都将当前用户名与其对应session存储到map中  
    35.             sessions.setAttribute("ifNull", "a");  
    36.             hUserMap.put(sUser, sessions);        
    37.             fUserMap.put(sUser, IpAdrr);  
    38.             application.setAttribute(sUser,hUserMap);  
    39.               
    40.             log.debug("登录的用户名:"+sUser);  
    41.             log.debug("登录的时间:"+cTime);  
    42.             log.debug("登录的IP地址:"+IpAdrr);  
    43.             log.debug("当前sessionId:"+sessions.getId());   
    44.               
    45.             //将登陆信息存入数据库  
    46.             dao.addLoginInfo(sUser, cTime, IpAdrr, sessions.getId(), "正常登陆");     
    47.         }  
    48.           
    49.     }  
    50. 校验用户是否已被剔出代码,并形成弹框提示状态:
      1. public boolean tUserState(String tUser,PageData pd){  
      2.           
      3.         String CurrentSessionId=pd.getSession().getId();      
      4.         ServletContext application=pd.getSession().getServletContext();  
      5.         //被踢掉的存储map  
      6.         HashMap<String, HttpSession> pMap=(HashMap<String, HttpSession>) application.getAttribute(tUser+"T");  
      7.         //在线map  
      8.         HashMap<String, HttpSession> zMap=(HashMap<String, HttpSession>) application.getAttribute(tUser);  
      9.   
      10.           
      11.          if(!(pMap==null)){  
      12.             //只有被踢掉的sessionid与请求的sessionid相同时才有提示框,也就是说只有被踢掉的浏览器才提示  
      13.             if(!(zMap.get(tUser).getId()).equals(CurrentSessionId)){  
      14.                 //检测到有同一用户被踢后,就将该用户信息在application中删除,防止其他用户登录检测到不为空  
      15.                 application.removeAttribute(tUser+"T");  
      16.                 return true;   
      17.             } else{  
      18.                 return false;  
      19.                     }  
      20.               
      21.          }else{  
      22.             return false;  
      23.          }  
      24.           
      25.           
      26.     }  
      27. 接收ajax参数,并向ajax返回用户状态代码:
        1. public void loginState(IRequestCycle cycle) throws Exception{  
        2.           
        3.         PageData pd = getPageData();  
        4.         IData data =pd.getData();  
        5.         IData mloginState=new DataMap();  
        6.         LoginBean bean = (LoginBean)BeanFactory.getBeanFactory().getBean(LoginBean.class);  
        7.         SimpleDateFormat mDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
        8.         String cTime=mDate.format(new Date());    
        9.         boolean mState=bean.tUserState(data.getString("tUser"),pd);  
        10.         log.debug("Myajax:"+data.getString("tUser"));  
        11.         String nState=String.valueOf(mState);  
        12.         mloginState.put("STATE", nState);  
        13.         log.debug("loginStateRun:"+nState+",time:"+cTime);  
        14.         pd.setAjaxData(mloginState);  
        15.       
        16.     }  
        17. html登陆页面cookie获取参数代码:
          1. function setCookie() {    
          2.         var Days = 60; //cookie 将被保存两个月     
          3.         var exp = new Date(); //获得当前时间     
          4.         exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000); //换成毫秒    
          5.         document.cookie =  "kang"+ "=" + escape($("#STAFF_LOGINID").val()) + ";expires=" + exp.toGMTString();    
          6.     }
          7. js文件ajax登陆状态监测代码:
            1.  $(function () {  
            2.   
            3.         setInterval("loginAjax()", 20000);  
            4.           
            5.           
            6.     });  
            7.       
            8.     function getCookie(name) {    
            9.         //取出cookie     
            10.         var strCookie = document.cookie;    
            11.         //cookie的保存格式是 分号加空格 "; "    
            12.         var arrCookie = strCookie.split("; ");    
            13.         for ( var i = 0; i < arrCookie.length; i++) {    
            14.             var arr = arrCookie[i].split("=");    
            15.             if (arr[0] == name) {    
            16.                 return arr[1];    
            17.             }    
            18.         }    
            19.         return "";    
            20.     }    
            21.       
            22. function loginAjax(){  
            23.     var t=getCookie("kang");  
            24.     var params = {page:"Home",   
            25.               listener:"loginState",  
            26.               param:'&tUser='+t,   
            27.               partId:null,   
            28.               formId:"loginForm",   
            29.               afterFn:afterState};  
            30.         $.ajaxSubmit(params);  
            31.                 
            32. }  
            33.   
            34. function afterState(data){  
            35.       
            36.     var state=data[0].STATE;  
            37.       
            38.     if(state=="true"){  
            39.   
            40.         layer.alert('您的账号已在别处登陆,请返回登录页重新登陆!', 8, '温馨提示');  
            41.   
            42.     }  
            43.       
            44. }  
            45.      写在最后,实现此功能还有其他方法,比如说用监听器监听等。本方法中尚存在不足,由于ajax的监听是每隔一段时间监测,所以提示弹框的实时性可能不是太高,若时间设置太短可能会对服务器造成较大的压力,但功能还是能实现。若有更好方案的同志请留言给我,我们可以一起讨论一下。
  • 相关阅读:
    Debian安装autoconf
    Linux 解决 bash ./ 没有那个文件或目录 的方法
    C语言strtok()函数:字符串分割
    java.util.logging.Logger使用详解 (转)
    java中Logger.getLogger(Test.class)
    jquery ajax中success与complete的执行顺序 (转)
    navicat如何导入sql文件和导出sql文件
    MySQL修改root密码的多种方法(转)
    查看三种MySQL字符集的方法(转)
    mysql 5.7.13 安装配置方法图文教程(linux) (转)
  • 原文地址:https://www.cnblogs.com/lanblogs/p/7503555.html
Copyright © 2011-2022 走看看