Java Web防止用户重复(同一用户同时)登录实现方式

相信我们在开发web工程的时候,都会遇到同一用户可以同时登录进系统的问题。对于开发的时候我们可能不是太关注这个问题,但对客户来说,他们肯定觉得是不可以的。那么我们在日常开发的过程中有几种解决方案。

1、如果我们的项目使用的是 Spring 框架的话,Spring security 就可以实现防止用户重复登录的问题。当然有些web工程可能对于权限的控制要求没有那么严格,单单为了一个登录功能去实现Spring security 就有些大材小用了。我们还有其他的解决方案。

2、数据库层面设计,可以为用户表加登录状态字段判断,登录成功后,修改状态为1,退出后修改状态为0。但是此种方案貌似也有缺陷,如果某个用户登录进系统之后,没有正常退出那就坑了,状态如何修改?肯定相应的要做个管理员清退功能,将该用户强制下线。此外每次登陆都去操作一下数据库是不是有些多余了呢?没关系,我们可以利用更简单的方式来实现。

3、我们可以利用 Servlet三大域对象 request、session、application(ServletContext)中的ServletContext,它是一个全局的储存信息的空间,服务器启动后就被创建,服务器停止后才销毁。

request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。

具体方案:将用户的登录信息保存在application里, 然后利用session监听器HttpSessionListener监听每一个登录用户的登录情况。

1、在自己项目的登录功能中添加如下代码

ServletContext application = session.getServletContext();
@SuppressWarnings("unchecked")
Map<String, Object> loginMap = (Map<String, Object>) application.getAttribute("loginMap");
if (loginMap == null) {
    loginMap = new HashMap<String, Object>();
}
for (String key : loginMap.keySet()) {
    if (login.getUser_id().equals(key)) {
	    if (session.getId().equals(loginMap.get(key))) {
	        return redirectUrl.append("login.action?mesg=")
		    .append(URLEncoder.encode(username + "在同一地点重复登录", "UTF-8")).toString();
	    } else {
                return redirectUrl.append("login.action?mesg=")
		    .append(URLEncoder.encode(username + "异地已登录,请先退出登录", "UTF-8")).toString();
	    }
    }
}
loginMap.put(login.getUser_id(),session.getId());
application.setAttribute("loginMap", loginMap);
// 将用户保存在session当中
session.setAttribute("user", user);
// session 销毁时间
session.setMaxInactiveInterval(10*60);

2、编写一个实现类 SessionListener,重写HttpSessionListener

/**
 * session监听器
 * 
 * @author Fyq
 *
 */
public class SessionListener implements HttpSessionListener {
 
	@Override
	public void sessionCreated(HttpSessionEvent httpSessionEvent) {
		
	}
 
	@Override
	public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
		HttpSession session = httpSessionEvent.getSession();
		SysUserModel user = (SysUserModel) session.getAttribute("user");
		if (user != null) {
			ServletContext application = session.getServletContext();
			@SuppressWarnings("unchecked")
			Map<String, Object> loginMap = (Map<String, Object>) application.getAttribute("loginMap");
			loginMap.remove(user.getUser_id());
			application.setAttribute("loginMap", loginMap);
			session.removeAttribute("user");
		}
	}
 
}

sessionCreated session创建的时候使用,这里如果我们需用做统计在线人数等功能时,可以自己去实现自己的逻辑代码了

sessionDestroyed session销毁的时候用,session 销毁时调用逻辑去清除登录信息。

上述session销毁时间可以按照自己实际需求去定。session监听器的作用是为了监听那些非正常退出系统的用户,清除登录信息用的。

3、退出系统的方法和监听器中销毁session方法中的逻辑大体相同,根据自身项目的实际情况去定

@RequestMapping(value = "/logout.action", method = RequestMethod.POST)
	public void loginOut(HttpServletRequest request, HttpServletResponse response) {
		HttpSession session = request.getSession();
		String user_id = request.getParameter("user_id");
		if (session != null) {
			try {
				session.removeAttribute("user");
				String failSN = user_id + Contants.JOIN_STR;
				if (session.getAttribute(failSN) != null) {
					session.removeAttribute(failSN);
				}
				ServletContext application = session.getServletContext();
				@SuppressWarnings("unchecked")
				Map<String, Object> loginMap = (Map<String, Object>) application.getAttribute("loginMap");
				loginMap.remove(user_id);
				application.setAttribute("loginMap", loginMap);
			} catch (Exception e) {
				e.printStackTrace();
				AJAXUtil.handleSuccess(response, false);
			}
		}
		AJAXUtil.handleSuccess(response, true);
	}

4、记得需要在web.xml中添加监听器

<listener>
    <listener-class>com.csdn.framework.SessionListener</listener-class>  
</listener>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值