同一账号同一时间在不同地点登陆实现登陆剔出功能

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

        先理一下思路,我们知道在客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是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都存入数据库中,以备出现问题可以进行查询。

--------------------------------------------------------------------------------------------下面上代码---------------------------------------------------------------------

校验用户是否登陆代码:

public void isLoaded(String sUser,HttpSession sessions,PageData pd) throws Exception{
		LoginDao dao=new LoginDao(pd);
		ServletContext application=pd.getSession().getServletContext();
		
		
		SimpleDateFormat mDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String cTime=mDate.format(new Date());
		String IpAdrr=dao.getClientIp(pd);
        HashMap<String, HttpSession> cMap=(HashMap<String, HttpSession>) application.getAttribute(sUser);

        try {
        	//判断是否当前用户名已登录
        	if(!(cMap==null)){
    			HttpSession mSession=cMap.get(sUser);
    			String mIP=fUserMap.get(sUser);
    			String mSessionId=mSession.getId();//被踢掉session
    			String cSessionId=sessions.getId();//在线session
    			
    			//判断是否为同一浏览器登陆
    			if(!(mSessionId.equals(cSessionId))){				
    				
    				passMap.put(sUser+"T", mSession);
    				application.setAttribute(sUser+"T", passMap);
    				dao.addLoginInfo(sUser, cTime, mIP, mSessionId, "用户在别处登陆");
    				if(!(mSession.getAttribute("ifNull")==null)){
    					mSession.invalidate();
    				}  				
    			}
    		}
        	
		} catch (Exception e) {
			log.debug("session已失效");
		}finally{
			//无论当前用户名登陆与否,都将当前用户名与其对应session存储到map中
			sessions.setAttribute("ifNull", "a");
			hUserMap.put(sUser, sessions);		
	        fUserMap.put(sUser, IpAdrr);
	        application.setAttribute(sUser,hUserMap);
			
			log.debug("登录的用户名:"+sUser);
			log.debug("登录的时间:"+cTime);
			log.debug("登录的IP地址:"+IpAdrr);
			log.debug("当前sessionId:"+sessions.getId()); 
			
			//将登陆信息存入数据库
			dao.addLoginInfo(sUser, cTime, IpAdrr, sessions.getId(), "正常登陆");	
		}
		
	}

校验用户是否已被剔出代码,并形成弹框提示状态:

public boolean tUserState(String tUser,PageData pd){
    	
    	String CurrentSessionId=pd.getSession().getId();   	
    	ServletContext application=pd.getSession().getServletContext();
    	//被踢掉的存储map
    	HashMap<String, HttpSession> pMap=(HashMap<String, HttpSession>) application.getAttribute(tUser+"T");
    	//在线map
    	HashMap<String, HttpSession> zMap=(HashMap<String, HttpSession>) application.getAttribute(tUser);

    	
     	 if(!(pMap==null)){
    		//只有被踢掉的sessionid与请求的sessionid相同时才有提示框,也就是说只有被踢掉的浏览器才提示
    		if(!(zMap.get(tUser).getId()).equals(CurrentSessionId)){
    			//检测到有同一用户被踢后,就将该用户信息在application中删除,防止其他用户登录检测到不为空
    			application.removeAttribute(tUser+"T");
    		    return true; 
    		} else{
    			return false;
                	}
    		
     	 }else{
     		return false;
     	 }
		
    	
    }
接收ajax参数,并向ajax返回用户状态代码:

public void loginState(IRequestCycle cycle) throws Exception{
    	
    	PageData pd = getPageData();
    	IData data =pd.getData();
    	IData mloginState=new DataMap();
    	LoginBean bean = (LoginBean)BeanFactory.getBeanFactory().getBean(LoginBean.class);
    	SimpleDateFormat mDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String cTime=mDate.format(new Date()); 	
    	boolean mState=bean.tUserState(data.getString("tUser"),pd);
    	log.debug("Myajax:"+data.getString("tUser"));
    	String nState=String.valueOf(mState);
    	mloginState.put("STATE", nState);
    	log.debug("loginStateRun:"+nState+",time:"+cTime);
    	pd.setAjaxData(mloginState);
    
    }
html登陆页面cookie获取参数代码:

function setCookie() {  
        var Days = 60; //cookie 将被保存两个月   
        var exp = new Date(); //获得当前时间   
        exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000); //换成毫秒  
        document.cookie =  "kang"+ "=" + escape($("#STAFF_LOGINID").val()) + ";expires=" + exp.toGMTString();  
    }  

js文件ajax登陆状态监测代码:
	$(function () {

		setInterval("loginAjax()", 20000);
		
		
	});
	
	function getCookie(name) {  
        //取出cookie   
        var strCookie = document.cookie;  
        //cookie的保存格式是 分号加空格 "; "  
        var arrCookie = strCookie.split("; ");  
        for ( var i = 0; i < arrCookie.length; i++) {  
            var arr = arrCookie[i].split("=");  
            if (arr[0] == name) {  
                return arr[1];  
            }  
        }  
        return "";  
    }  
	
function loginAjax(){
	var t=getCookie("kang");
	var params = {page:"Home", 
		      listener:"loginState",
	          param:'&tUser='+t, 
		      partId:null, 
		      formId:"loginForm", 
		      afterFn:afterState};
        $.ajaxSubmit(params);
              
}

function afterState(data){
	
	var state=data[0].STATE;
	
	if(state=="true"){

		layer.alert('您的账号已在别处登陆,请返回登录页重新登陆!', 8, '温馨提示');

	}
	
}
       写在最后,实现此功能还有其他方法,比如说用监听器监听等。本方法中尚存在不足,由于ajax的监听是每隔一段时间监测,所以提示弹框的实时性可能不是太高,若时间设置太短可能会对服务器造成较大的压力,但功能还是能实现。若有更好方案的同志请留言给我,我们可以一起讨论一下。


  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值