核心是通过 缓存、Cookie以及SpringMVC拦截器 实现
登陆时以用户id为key在缓存中保存时间戳 在cookie中以一个全局变量为key保存时间戳
String times = new Date().getTime() + "";
memCache.put(userId + "mem_time_key", times); WebUtils.setCookie(response,"flag", times, 30);
我们知道cookie是保存在浏览器本地的,缓存保存在服务端
此时 还是这个用户 在另一个终端登录,会重复 上面代码的操作,更新在服务端的缓存 key相同 ,而value时间戳发生了变化
下一步,需要在每个页面引入功能写入功能js文件即可,写一个实现每次载入页面都会定时器10s执行的查询后台的 flag 对应的缓存的vlaue 并与本地cookie中的时间戳相比较,如果不一致说明,用户在别的浏览器登陆过,则可以清空cookie 强制退出,由于 后一次登录更改服务器缓存的时间戳,所以前一次登录会被强制退出。
function callbackFun() {
if (isLogin()) {
$.ajax({
url: "/check/userIsLogin.json",
data: {},
type: "post",
dataType: "json",
async: false,
success: function (result) {
if (result.success == false) {
if (result.message == "OthersIsLogin") {
dialog("下线提示", "您的账号在其他地方登录,若非本人操作,请重新登录。", 6, '/index');
DeleteCookie("flag"); //删除本地时间戳
}
} else {
setTimeout(callbackFun, 10000); //延时递归调用自己,间隔调用时间,单位毫秒
}
}
});
}
}
后台Jvav代码 比较时间戳
String times = (String)memCache.get(userId+"mem_time_key");
if (ObjectUtils.isNotNull(userId) && ObjectUtils.isNotNull(times)) {
String cookieTime = WebUtils.getCookie(request, "flag");
if (StringUtils.isNotEmpty(times) && StringUtils.isNotEmpty(cookieTime) && !times.equals(cookieTime)) {
memCache.remove(MemConstans.USEREXPAND_INFO + userId); //清除用户信息(不包含时间戳)
WebUtils.deleteCookie(request, response, CommonConstants.USER_SINGEL_ID);//清除用户cookie信息
json = this.getJsonMap(false, "OthersIsLogin", null);
}
}
如果实现随时可修改的是否检测登录唯一性呢?
其实更灵活的办法是把上述判断代码写入springmvc的拦截器的前置增强中
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.preHandle(request, response, handler);
JsonObject userJsonObject = SingletonLoginUtils.getLoginUser(request);
if(ObjectUtils.isNotNull(userJsonObject)){ //是否有登录用户判断 防止空指针
if(ischeck){ //可从数据库查询 是否检测唯一性标识
//登录状态的验证,是否被其他人踢掉
//上述Java判断代码功能一致即可
}
}else{//未登录时跳转到登录页面
if(request.getRequestURL().indexOf("/mobile")>-1){
response.sendRedirect("/mobile/login");
}else{
response.sendRedirect("/login");
}
}
}