您的位置:首页 > 其它

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

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

        先理一下思路,我们知道在客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是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的监听是每隔一段时间监测,所以提示弹框的实时性可能不是太高,若时间设置太短可能会对服务器造成较大的压力,但功能还是能实现。若有更好方案的同志请留言给我,我们可以一起讨论一下。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: