java web 用户单点登录的方案的基本实现
2015-12-16 19:23
811 查看
在实验室刚刚结束的项目中,有这样一个需求,一个账号同时只能在一个地方登录,如果在其他地方登录则提示已在别处登录,直到已登录账号失效或退出,同时,同一浏览器同时只能登录一个用户。
首先,考虑不能重复登录的问题。在项目中,我使用session来存储用户的信息,用户登录时,创建一个session,将用户名,用户逻辑Id,登录时间等属性存放到该session中。考虑使用Application来实现禁止重复登录。定义一个Map<Long,String>类型的变量loginUserMap。其每条记录存储登录用户的逻辑Id和对应session的sessionId。这样,每次用户登录的时候遍历loginUserMap,如果没有对应的userlogicId或sessionId则允许登录,否则提示已在别处登录。
在用户退出的操作中,将loginUserMap中对应的用户logicId和sessionId清除,同时清除session中的用户信息。
首先,考虑不能重复登录的问题。在项目中,我使用session来存储用户的信息,用户登录时,创建一个session,将用户名,用户逻辑Id,登录时间等属性存放到该session中。考虑使用Application来实现禁止重复登录。定义一个Map<Long,String>类型的变量loginUserMap。其每条记录存储登录用户的逻辑Id和对应session的sessionId。这样,每次用户登录的时候遍历loginUserMap,如果没有对应的userlogicId或sessionId则允许登录,否则提示已在别处登录。
// 判断是否重复登录 isloginexists = false; ifsessioninvalidate = false; loginUserMap = (Map<Long, String>) acx.getApplication().get(WebConstant.LOGIN_USER_MAP); if (loginUserMap == null) { loginUserMap = new HashMap<Long, String>(); } HttpServletRequest request = ServletActionContext.getRequest(); String sessionId = request.getSession(false).getId(); System.out.println("sessionId" + sessionId); for (Long userlogicId2 : loginUserMap.keySet()) { if (!userlogicId2.equals(userlogicId) && !loginUserMap.containsValue(sessionId)) { // 不同浏览器不允许相同用户重复登录 continue; } if(userlogicId2.equals(userlogicId)&&!loginUserMap.containsValue(sessionId)){ setIfsessioninvalidate(true); } isloginexists = true; break; } if (isloginexists) { setTip("loginexists"); if(ifsessioninvalidate==true){ request.getSession(false).invalidate(); } } else { loginUserMap.put(userlogicId, sessionId); acx.getApplication().put(WebConstant.LOGIN_USER_MAP,loginUserMap); acx.getSession().put(WebConstant.USER_ID, getUsername()); acx.getSession().put(WebConstant.USER_LOGICID,userManageService.findbyUsername(getUsername()).getLogicId()); acx.getSession().put(WebConstant.LOGIN_TIME, new Date()); }
在用户退出的操作中,将loginUserMap中对应的用户logicId和sessionId清除,同时清除session中的用户信息。
Map<Long, String> loginUserMap = (Map<Long, String>)acx.getApplication().get(WebConstant.LOGIN_USER_MAP); String username=userManageService.findByLogicId(userlogicId).getUserName(); if(loginUserMap.containsKey(userlogicId)){ loginUserMap.remove(userlogicId); } session.getServletContext().setAttribute("loginUserMap", loginUserMap); Long id=(Long) session.getAttribute(WebConstant.USER_LOGICID); if(id!=null) this.userManageService.userLogout(id); session.removeAttribute(WebConstant.USER_ID); session.removeAttribute(WebConstant.USER_LOGICID); session.removeAttribute(WebConstant.LOGIN_TIME); //使Session失效 session.invalidate(); response.setHeader("Cache-Control","no-cache"); response.setHeader("Cache-Control","no-store"); response.setDateHeader("Expires", 0);在session失效的监听器处理中,也做相同的操作,保证登录session超时时从loginUserMap中删除该用户,以保证后继账号能够正常登录。
public class SessionListener implements HttpSessionListener{ @Override public void sessionCreated(HttpSessionEvent event) { } @Override public void sessionDestroyed(HttpSessionEvent event) { //监听session的失效和销毁 HttpSession session=event.getSession(); ServletContext application=session.getServletContext(); try{ String username=(String) session.getAttribute(WebConstant.USER_ID); Long userlogicId=(Long)session.getAttribute(WebConstant.USER_LOGICID); Map<Long, String> loginUserMap = (Map<Long, String>)application.getAttribute(WebConstant.LOGIN_USER_MAP); if(loginUserMap.containsKey(userlogicId)) loginUserMap.remove(userlogicId); application.setAttribute(WebConstant.LOGIN_USER_MAP, loginUserMap); System.out.println("session:"+session.getId()+"已失效"); } catch(Exception e){ System.out.println(e.getMessage()); } } }到这里,基本能做到限制用户的重复登录了,但是靠这些异常情况依然无法处理,如用户使用过程中关闭浏览器,再次登录时,由于信息记录在服务器端的application中且未按照正常安全退出流程执行,则执行登录操作会提示"已在别处登录"。要解决这个问题,参考博文《java web用户单点登录异常情况处理之用户的非正常退出》。
相关文章推荐
- OutOfMemory Java heap space解决方法
- Eclipse 调试技巧
- 2016届阿里实习生java研发岗一面二面三面四面经验分享
- Java collection
- java web中使用log4j路径的事
- Spring整合LogBack
- JAVA开发环境变量配置
- 诊断Java中的内存泄露
- java--反射和注解
- 深度分析 Java 的 ClassLoader 机制(源码级别)
- JDK配置完成以后,“.jar”文件双击依旧不能运行的问题
- java日历程序版本
- Java中使用jdbc连接数据库
- Java 调用构造器会不会一定产生新对象
- 深度分析 Java 的 ClassLoader 机制(源码级别)
- 轻量级JavaEE企业应用实战(五)
- Java并发编程 - Latch和Barrier的区别
- MyEclipse过期后重新注册序列号的方式
- 创建存储过程和java调用存储过程
- [Java学习] Java插入排序实现