您的位置:首页 > 编程语言 > Java开发

java web项目防止多用户重复登录解决方案

2015-10-23 09:21 585 查看
目前web项目中,很多情况都是可以让同一个账户信息在不同的登录入口登录这次,这样子就不那么美好了。现在有两种解决方案:1、将用户的登录信息用一个标志位的字段保存起来,每次登录成功就标记1,注销登录就标记为0,当标记为1的时候不允许别人登录。2、将用户的登录信息保存在application内置作用域内, 然后利用session监听器监听每一个登录用户的登录情况。很显然,第一种方式 每次登录 都需要操作数据库,多了一些不必要的性能开销,而且在登录状态下 万一突然电脑关闭了,那就永远都不能登录了,可用性比较低。但是第二种方式就不一样了,可操作性强,很方便维护所有在线用户的信息。接下来 主要介绍第二种方式的具体实现:1、在处理登录的login方法中,先查询数据库验证下该用户是否存在,如果存在 判断该登录账户是否已经锁定了, 然后从application内置作用域对象中取出所有的登录信息,查看该username账户是否已经登录,如果登录了,就友好提示下,反之表示可以登录,将该登录信息保存在application中。代码://没有使用零配置前 每个访问的方法都要加上@Action ,否则404@Action(value="login", results={@Result(name="index", location="index.jsp"),})public String login() throws Exception {try{User result = userService.login(user.getFuUserName(), user.getFuPassword());if(result!=null){if(result.getFuStatus()!=null && result.getFuStatus()==0){super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已被锁定!");return "error";}Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP);boolean isExist = false;String sessionId = super.getSessionId(false);if(loginUserMap==null){loginUserMap = new HashMap<String, String>();}for (String username : loginUserMap.keySet()) {//判断是否已经保存该登录用户的信息 并且 如果是同一个用户进行重复登录那么允许登录if(!username.equals(result.getFuUserName()) || loginUserMap.containsValue(sessionId)){continue;}isExist = true;break;}if(isExist){super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已登录!");return "error";}else {loginUserMap.put(result.getFuUserName(), sessionId);}//登录成功super.setSessionAttr(Constant.LOGIN_USER, result);super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap);logger.info(result.getFuUserName() + " 登录成功!");//如果 session中fromUrl有值,就跳转到该页面String fromUrl = (String)super.getSessionAttr(Constant.FROM_URL);if(fromUrl!=null){super.setSessionAttr(Constant.FROM_URL, null);super.getResponse().sendRedirect(fromUrl.toString());return null;}return "index";}}catch (Exception e) {e.printStackTrace();logger.info("登录失败: "+e.getMessage());}super.setRequestAttr("message", "用户名或密码错误");return "error";}//没有使用零配置前 每个访问的方法都要加上@Action ,否则404@Action(value="login", results={@Result(name="index", location="index.jsp"),})public String login() throws Exception {try{User result = userService.login(user.getFuUserName(), user.getFuPassword());if(result!=null){if(result.getFuStatus()!=null && result.getFuStatus()==0){super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已被锁定!");return "error";}Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP);boolean isExist = false;String sessionId = super.getSessionId(false);if(loginUserMap==null){loginUserMap = new HashMap<String, String>();}for (String username : loginUserMap.keySet()) {//判断是否已经保存该登录用户的信息 并且 如果是同一个用户进行重复登录那么允许登录if(!username.equals(result.getFuUserName()) || loginUserMap.containsValue(sessionId)){continue;}isExist = true;break;}if(isExist){super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已登录!");return "error";}else {loginUserMap.put(result.getFuUserName(), sessionId);}//登录成功super.setSessionAttr(Constant.LOGIN_USER, result);super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap);logger.info(result.getFuUserName() + " 登录成功!");//如果 session中fromUrl有值,就跳转到该页面String fromUrl = (String)super.getSessionAttr(Constant.FROM_URL);if(fromUrl!=null){super.setSessionAttr(Constant.FROM_URL, null);super.getResponse().sendRedirect(fromUrl.toString());return null;}return "index";}}catch (Exception e) {e.printStackTrace();logger.info("登录失败: "+e.getMessage());}super.setRequestAttr("message", "用户名或密码错误");return "error";}
<p style="margin-top: 0px; margin-bottom: 0px; padding-top: 15px; padding-bottom: 0px; text-indent: 2em; color: rgb(64, 64, 64); font-family: 'Microsoft YaHei', SimHei, 微软雅黑, 黑体; font-size: 14px; line-height: 25px;">2、登录入口处理完之后,考虑到回话结束的话,那么对应的登录用户也应该相应的注销登录。我们可以写一个Session监听器,监听sessioon销毁的时候,我们将登录的用户注销掉,也就是从application中移除。表示该用户已经下线了。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 15px; padding-bottom: 0px; text-indent: 2em; color: rgb(64, 64, 64); font-family: 'Microsoft YaHei', SimHei, 微软雅黑, 黑体; font-size: 14px; line-height: 25px;">代码如下:</p>
<pre name="code" class="java">public class SessionListener implements HttpSessionListener,ServletContextListener{private int count;private ServletContext servletContext = null;public SessionListener() {count =a3440;}private Logger logger = Logger.getLogger(this.getClass());@Overridepublic void sessionCreated(HttpSessionEvent event) {count++;setContext(event);logger.info("***************the  http session is created...***************");}@Overridepublic void sessionDestroyed(HttpSessionEvent event) {//在session销毁的时候 把loginUserMap中保存的键值对清除User user = (User)event.getSession().getAttribute("loginUser");if(user!=null){Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap");loginUserMap.remove(user.getFuUserName());event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap);}count--;setContext(event);logger.info("***************the  http session is destroyed...***************");}public void setContext(HttpSessionEvent httpSessionEvent){httpSessionEvent.getSession().getServletContext().setAttribute("online", count);}@Overridepublic void contextDestroyed(ServletContextEvent servletcontextevent) {this.servletContext = null;logger.info("***************the  servlet context is destroyed...***************");}@Overridepublic void contextInitialized(ServletContextEvent servletcontextevent) {this.servletContext = servletcontextevent.getServletContext();logger.info("***************the  servlet context is initialized...***************");}public class SessionListener implements HttpSessionListener,ServletContextListener{private int count;private ServletContext servletContext = null;public SessionListener() {count = 0;}private Logger logger = Logger.getLogger(this.getClass());@Overridepublic void sessionCreated(HttpSessionEvent event) {count++;setContext(event);logger.info("***************the  http session is created...***************");}@Overridepublic void sessionDestroyed(HttpSessionEvent event) {//在session销毁的时候 把loginUserMap中保存的键值对清除User user = (User)event.getSession().getAttribute("loginUser");if(user!=null){Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap");loginUserMap.remove(user.getFuUserName());event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap);}count--;setContext(event);logger.info("***************the  http session is destroyed...***************");}public void setContext(HttpSessionEvent httpSessionEvent){httpSessionEvent.getSession().getServletContext().setAttribute("online", count);}@Overridepublic void contextDestroyed(ServletContextEvent servletcontextevent) {this.servletContext = null;logger.info("***************the  servlet context is destroyed...***************");}@Overridepublic void contextInitialized(ServletContextEvent servletcontextevent) {this.servletContext = servletcontextevent.getServletContext();logger.info("***************the  servlet context is initialized...***************");}web.xml中配置如下:[html] view plaincopyprint?<!-- session listener --><listener><listener-class>com.facelook.util.SessionListener</listener-class></listener><!-- session listener --><listener><listener-class>com.facelook.util.SessionListener</listener-class></listener>
<span style="color: rgb(64, 64, 64); font-family: 'Microsoft YaHei', SimHei, 微软雅黑, 黑体; font-size: 14px; line-height: 25px; text-indent: 28px;">3、另外,还有一个问题,如果说登录的用户突然关闭了浏览器而没有点击退出按钮。那么可以利用beforeunload 事件,在浏览器刷新或者关闭的时候触发。</span>
<span style="color: rgb(64, 64, 64); font-family: 'Microsoft YaHei', SimHei, 微软雅黑, 黑体; font-size: 14px; line-height: 25px; text-indent: 28px;"></span>
<span style="color: rgb(64, 64, 64); font-family: 'Microsoft YaHei', SimHei, 微软雅黑, 黑体; font-size: 14px; line-height: 25px; text-indent: 28px;"></span><div class="line number1 index0 alt2" style="font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; line-height: 14.3px; font-size: 13px; color: rgb(64, 64, 64); margin: 0px !important; padding: 0px 1em !important; border-radius: 0px !important; border: 0px !important; bottom: auto !important; float: none !important; left: auto !important; outline: 0px !important; overflow: visible !important; position: static !important; right: auto !important; top: auto !important; vertical-align: baseline !important; width: auto !important; box-sizing: content-box !important; min-height: auto !important; background-image: none !important; background-attachment: initial !important; background-color: rgb(245, 245, 245); background-size: initial !important; background-origin: initial !important; background-clip: initial !important; background-position: initial !important; background-repeat: initial !important;"><pre name="code" class="javascript">//在刷新或关闭时调用的事件$(window).bind('beforeunload',function(){$.ajax({url:"${ctx}/system/user/user!logout.action",type:"post",success:function(){alert("您已退出登录");}}););//在刷新或关闭时调用的事件$(window).bind('beforeunload',function(){$.ajax({url:"${ctx}/system/user/user!logout.action",type:"post",success:function(){alert("您已退出登录");}});});

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息