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的监听是每隔一段时间监测,所以提示弹框的实时性可能不是太高,若时间设置太短可能会对服务器造成较大的压力,但功能还是能实现。若有更好方案的同志请留言给我,我们可以一起讨论一下。
  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/lanblogs/p/7503555.html
Copyright © 2011-2022 走看看