Java 多用户登录限制的实现方法

Wesley13
• 阅读 332

Java 多用户登录限制的实现方法 现在有两种解决方案: 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"; } 2、登录入口处理完之后,考虑到会话结束的话,那么对应的登录用户也应该相应的注销登录。我们可以写一个Session监听器,监听sessioon销毁的时候,我们将登录的用户注销掉,也就是从application中移除。表示该用户已经下线了。 代码如下:

package com.facelook.util; import java.util.Map; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.apache.log4j.Logger; import com.facelook.entity.User; public class SessionListener implements HttpSessionListener{ private Logger logger = Logger.getLogger(this.getClass()); @Override public void sessionCreated(HttpSessionEvent event) { } @Override public 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); } } } web.xml中配置如下:

com.facelook.util.SessionListener 3、另外,还有一个问题,如果说登录的用户突然关闭了浏览器或者页面而没有点击退出按钮。那么可以利用beforeunload 事件,在浏览器刷新或者关闭的时候触发。

//在刷新或关闭时调用的事件 $(window).bind('beforeunload',function(){ $.ajax({ url:"${ctx}/system/user/user!logout.action", type:"post", success:function(){ alert("您已退出登录"); } }); ); 但是如果一些客观原因,比如电脑突然关机,自动重启,等等,这些就没法避免了,所以只能等待服务器端的session会话重置之后才可以再登录。 除非 做一个 统计所有在线人员的模块,管理员在里面进行在线人员的登录登出的状态管理,把那些有问题的登录用户直接销毁掉。 接下来简单介绍下在线人员模块的管理: 1、首先需要一个session监听器来监听所有的回话create的情况,这时候每次创建一个session就可以count+1 ,然后销毁的时候count-1 ,另外还需要一个ServletContext的监听器来监听web应用的生命周期,获取servletContext对象,然后将在线人员总数统计出来存放进去; 具体代码如下:

package com.facelook.util; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.apache.log4j.Logger; import com.facelook.entity.User; public class SessionListener implements HttpSessionListener,ServletContextListener{ private int count; private ServletContext servletContext = null; public SessionListener() { count = 0; } private Logger logger = Logger.getLogger(this.getClass()); @Override public void sessionCreated(HttpSessionEvent event) { count++; setContext(event); logger.info("the http session is created..."); } @Override public 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); } @Override public void contextDestroyed(ServletContextEvent servletcontextevent) { this.servletContext = null; logger.info("the servlet context is destroyed..."); } @Override public void contextInitialized(ServletContextEvent servletcontextevent) { this.servletContext = servletcontextevent.getServletContext(); logger.info("the servlet context is initialized..."); } } 2、在UserAction中创建管理在线用户的模块的方法,并且支持强制退出的功能;

/** * 退出登录

  • @return
  • @throws ServletException
  • @throws IOException / public String logout() throws ServletException, IOException{ try { Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP); User user = (User) super.getSessionAttr(Constant.LOGIN_USER); super.removeAttribute(Constant.LOGIN_USER_MAP); loginUserMap.remove(user.getFuUserName()); super.setApplicationAttr(Constant.LOGIN_USER_MAP,loginUserMap); logger.info("退出登录成功!"); } catch (Exception e) { e.printStackTrace(); logger.error("退出登录失败: "+e.getMessage()); } return INPUT; } /*
  • 在线用户管理
  • @return / public String loginManager(){ return SUCCESS; } /*
  • 强制退出其他用户
  • @return */ public String logoutOther(){ try { String username = ServletActionContext.getRequest().getParameter("username"); Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP); if(username!=null && loginUserMap.containsKey(username)){ loginUserMap.remove(username); super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap); } } catch (Exception e) { e.printStackTrace(); logger.info("强制退出失败: "+e.getMessage()); } return null; } 3、在管理页面加载在线用户的列表; 对应的方法定义完毕之后,然后再在对应的管理页面添加在线列表,具体如下:

<%@page import="java.util.Map"%> <%@page import="java.util.Map.Entry"%> <%@ page language="java" pageEncoding="UTF-8" %> <%@ include file="/common/taglib.jsp" %>

欢迎来到Facelook <%@ include file="/common/resource.jsp" %> <%@ include file="/common/header.jsp" %>
<%@ include file="/common/lefter.jsp" %>

登录列表

<% Map map = (Map)application.getAttribute("loginUserMap"); out.println("目前共有"+map.size()+"个用户在线!!"); %> <%for(Entry m : map.entrySet()){%> <%}%>
<%=m.getKey()%> 强制退出
<%@ include file="/common/footer.jsp" %> <%@ include file="/common/message.jsp" %> 好了启动部署项目,然后启动服务,进入在线用户管理模块,简单效果如下图:

需要注意的是:当前登录用户 不允许强制退出自己的登录信息。 这样子,基本上可以实现防止多用户登录的案例了!

点赞
收藏
评论区
推荐文章
kenx kenx
2年前
SpringBoot @ModelAttribute 用法
前言项目中遇到这么一个使用场景,用户的登录信息给予token保存,在需要有登录信息的地方,每次都要去获取用户Id,但每次在请求方法中去获取用户信息,代码重复,冗余,很low于是想到了用@ModelAttribute这个属性使用场景不用@ModelAttribute时候在需要用户信息的请求中每次需要单独获取用户信息JavaStringtoken
_dolphin _dolphin
2年前
.net core Cookie的使用
缘起:  公司领导让我做一个测试的demo,功能大概是这样的:用户通过微信扫一扫登陆网站,如果用户登录过则直接进入主界面,否则就保留在登录界面。实现方法:  首先先把网站地址生成个二维码,在扫描二维码后去获取Cookie如果有值那么就证明登录过直接跳转到主界面,如果Cookie不存在用户通过登录记录的用户信息并保存到Cookie。什么是Cookie:  储存
Easter79 Easter79
2年前
springboot+redis实现session共享
!(https://oscimg.oschina.net/oscnet/b41e3a6367d04dee9f4e4acdbce5c45c.jpg)1.场景描述因项目访问压力有点大,需要做负载均衡,但是登录使用的是公司统一提供的单点登录系统,需要做session共享,否则假如在A机器登录成功,在B机器上操作就会存在用户未登录情况。
Stella981 Stella981
2年前
Linux用户登录记录日志和相关查看命令汇总(转)
\1utmp、wtmp、btmp文件Linux用户登录信息放在三个文件中:1  /var/run/utmp:记录当前正在登录系统的用户信息,默认由who和w记录当前登录用户的信息,uptime记录系统启动时间;2  /var/log/wtmp:记录当前正在登录和历史登录系统的用户信息,默认由las
Stella981 Stella981
2年前
Linux仅可使用SFTP登录到指定目录(无法使用ssh、ftp、telnet)
目标:1.用户appmon只能使用sftp登录,拒绝ssh、ftp、telnet等方式登录。2.用户登录默认根目录为/shucang6/mpppoc/common,其父层目录不可见。3.登录后子目录data01和software内所有文件与子目录,仅允许下载,不允许上传和修改。4.登录后子目录result内所有文件与子目录,可允许下载
Stella981 Stella981
2年前
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法参考文章:(1)Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.codeprj.com%2Fblo
Wesley13 Wesley13
2年前
HttpHandler
 今天简单的做下HttpHandler的练习:只有登录用户才能下载images下地图片文件(Session中标识是否登录),如果用户没有登录则首先重定向到登录界面让用户登录,用户登录成功则跳转到下载列表页面,下载链接固定写好即可。如果登录用户是普通用户则在图片左上角加上“免费用试用”的字样。1.首先建立名为UserAuthority的数据库,然后新建
Stella981 Stella981
2年前
Spring Security使用详解7(注销登录配置)
默认情况下,SpringSecurity提供了注销接口是/logout,访问这个接口即可注销当前登录用户并且自动跳转到登录页。如果需要修改注销接口,或者想在注销时做一些业务逻辑,或者注销后不是跳转到登录页而是返回一段JSON提示,只需在一些简单配置即可。七、注销登录配置1、样例代码首先修改SpringSecurit
Wesley13 Wesley13
2年前
Java 可以用已知帐号登录,且可以注册后登录的小程序
|需求说明1、写一个注册和登录功能,使用已知的帐号和密码可以直接登录,如果没有帐号,注册后可以用刚注册的帐号登录2、注册的时候,如果帐号已经存在,不能注册3、注册的时候,设置两次密码,如果两次密码设置得不同,不能注册4、登录的时候,密码输错三次,锁定帐号5、登录的时候,如果没有这个帐号,则提醒用户注册,注册后可以登录6、登录的时候
Wesley13 Wesley13
2年前
mysql学习总结(三)
1.SQL注入     1)什么是sql注入:         例如:用户在网页进行登录操作时,输入数据库语句,导致网页的登录限制失效,不需要输入用户名和密码,用户可以输入语句就登录网页     2)出现sql注入的原因:        因为太相信用户的输入,导致我们在接收用户