Java实现网页端session有效期的管理
网页前端请求服务器完成登录后,会获取一个session会话。session会有一个有效期,有效期过后服务器应该要告诉前端需要重新登录。如果在不同的浏览器登录,前者的会话也应该失效。本文将介绍如何实现这样的功能,包括"前端请求后端判断会话有效期JS代码"、“服务器后端拦截有用户请求代码”。
1、前端请求后端判断会话有效期JS代码。
前端使用了Layui前端框架,使用ajax请求后端。在调用ajax请求服务器时,首先判断session是否过期、有效:
$(document).ajaxComplete(function (event, xhr, settings) {
console.log("监听到了");
console.log(xhr);
console.log(event)
console.log(xhr.getResponseHeader("sessionStatus"));
console.log("staffLoginUrl" + xhr.getResponseHeader("staffLoginUrl"));
console.log("bxstaffLoginUrl=" + xhr.getResponseHeader("bxstaffLoginUrl"));
layui.use('layer', function () {
var layer = layui.layer; //引用layui弹出层模块
if (xhr.getResponseHeader("sessionStatus") == "timeOut") {
if (xhr.getResponseHeader("staffLoginUrl")) {
window.top.layer.alert('登录过期,请重新登录...', {
cancel: function () {
window.top.location.href = xhr.getResponseHeader("staffLoginUrl");
}
}, function (index) {
window.top.location.href = xhr.getResponseHeader("staffLoginUrl");
layer.close(index);
});
} else if (xhr.getResponseHeader("bxstaffLoginUrl")) {
window.top.layer.alert('登录过期,请重新登录...', {
cancel: function () {
window.top.location.href = xhr.getResponseHeader("bxstaffLoginUrl");
}
}, function (index) {
window.top.location.href = xhr.getResponseHeader("bxstaffLoginUrl");
layer.close(index);
});
} else {
window.top.layer.alert('请求超时请重新登陆 !', function (index) {
layer.close(index);
});
}
} else if (xhr.getResponseHeader("sessionStatus") == "duplicatedSession") {
window.top.layer.alert('你已经在其它地方登录', {
cancel: function () {
window.top.location.href = xhr.getResponseHeader("staffLoginUrl");
}
}, function (index) {
window.top.location.href = xhr.getResponseHeader("staffLoginUrl");
console.log(xhr.getResponseHeader("staffLoginUrl"));
layer.close(index);
});
}
})
});
2、服务器后端拦截有用户请求代码。
新建StaffLoginInterceptor类,继承了Filter过滤器,这样用户的请求都将被StaffLoginInterceptor类所拦截。
从session中获取登录信息staff:
/*
* 超时处理,ajax请求超时设置超时状态,页面请求超时则返回提示并重定向 session.getAttribute("")是获取到登录人的session信息
*/
Staff staff = (Staff) session.getAttribute(EnumSession.SESSION_Staff.toString());
如果 staff为null,说明用户未登录或登录已失效,此时需要告诉前端让用户重新登录
if (staff == null && bxstaff == null && vip == null) {
handleAnyOneLoginWithoutSession(request, response, httpRequest, httpResponse, session, loginUrl, staffLoginUrl, bxstaffLoginUrl, vipLoginUrl);
}
private void handleAnyOneLoginWithoutSession (ServletRequest request, ServletResponse response, HttpServletRequest httpRequest, HttpServletResponse httpResponse, HttpSession session, String loginUrl, String staffLoginUrl,
String bxstaffLoginUrl, String vipLoginUrl) throws ServletException, IOException {
logger.info("拦截到的URL=" + httpRequest.getRequestURL() + " Cookie=" + httpRequest.getCookies() + " SessionID=" + session.getId());
// 判断是否为ajax请求
if (httpRequest.getHeader("x-requested-with") != null && httpRequest.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
httpResponse.addHeader("sessionStatus", "timeOut"); // 返回超时标识
logger.info("url=" + loginUrl);
// 判断当前登录的是哪个页面,跳转到相应的页面
if (loginUrl.equals(staffLoginUrl)) {
httpResponse.addHeader("staffLoginUrl", loginUrl);// 返回url
httpRequest.getRequestDispatcher(staffLoginUrl).forward(request, response);
} else if (loginUrl.equals(bxstaffLoginUrl)) {
httpResponse.addHeader("bxstaffLoginUrl", bxstaffLoginUrl);// 返回url
httpRequest.getRequestDispatcher(bxstaffLoginUrl).forward(request, response);
} else if (loginUrl.equals(vipLoginUrl)) {
httpResponse.addHeader("vipLoginUrl", vipLoginUrl);// 返回url
httpRequest.getRequestDispatcher(vipLoginUrl).forward(request, response);
}
// chain.doFilter(request, response);// 不可少,否则请求会出错
} else { // 非ajax请求,让其直接跳转到登录页面
String str = "";
if (session.getAttribute(EnumSession.SESSION_POS.toString()) == null) {
str = "<script language='javascript'>" + "window.top.location.href='" + loginUrl + "';</script>";
httpResponse.addHeader("sessionStatus", "timeOut"); // 返回超时标识
}
response.setContentType("text/html;charset=UTF-8");
try {
PrintWriter writer = response.getWriter();
writer.write(str);
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果session不为null,说明已经用户已经登录过,判断session是否有效(有可能是不同浏览器传来的session)。
关键方法为needToIntercept,返回true则说明session无效,用户需重新登录:
if (loginGuard.needToIntercept(company.getSN(), staff.getID(), posID, session)) {
String str = null;
if (posID == BaseAction.INVALID_POS_ID) { // 这是网页端上的操作
// 判断是否为ajax请求
if (httpRequest.getHeader("x-requested-with") != null) {
httpResponse.addHeader("staffLoginUrl", loginUrl);// 返回url
httpResponse.addHeader("sessionStatus", "duplicatedSession"); // 返回单点登录标识
str = "<script language='window.top.location.href='" + loginUrl + "';</script>";// ......
} else {
str = "<script language='javascript'>alert('你已经在其它地方登录'); window.top.location.href='" + loginUrl + "';</script>";
}
} else { // 这是POS端上的操作
Map<String, Object> params = new HashMap<String, Object>();
params.put(BaseAction.JSON_ERROR_KEY, EnumErrorCode.EC_DuplicatedSession.toString());
params.put(BaseAction.KEY_HTMLTable_Parameter_msg, "你已经在其它地方登录");
str = JSONObject.fromObject(params, JsonUtil.jsonConfig).toString();
}
response.setContentType("text/html;charset=UTF-8");
try {
PrintWriter writer = response.getWriter();
writer.write(str);
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
needToIntercept方法主要是用了hashmap缓存了前端最新的已登录的用户session,所以只需要判断当前session与缓存中的session是否一致,即可判断出该session是否有效:
public boolean needToIntercept(String companySN, int staffID, int posID, HttpSession session) {
if ((posID != BaseAction.INVALID_POS_ID && posID <= 0) || staffID <= 0) {
return true;
}
boolean needToIntercept = false;
lock.writeLock().lock();
LoginDevice currentLoginDevice = mapStaffLoginDevice.get(generateKey(companySN, staffID));
if (currentLoginDevice != null) {
if (posID == BaseAction.INVALID_POS_ID) {// 网页端登录
if (currentLoginDevice.getClientSessionOfWeb().hashCode() != session.hashCode()) {
needToIntercept = true;
}
} else {// POS机上登录
if (currentLoginDevice.getPosIDOfPos() != posID) {
needToIntercept = true;
}
}
}
lock.writeLock().unlock();
return needToIntercept;
}