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

目前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 loginUserMap = (Map) super.getApplicationAttr(Constant.LOGIN_USER_MAP);

boolean isExist = false;

String sessionId = super.getSessionId(false);

if(loginUserMap==null){

loginUserMap = new HashMap();

}

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 loginUserMap = (Map)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 loginUserMap = (Map)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 loginUserMap = (Map) 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 loginUserMap = (Map) 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、在管理页面加载在线用户的列表;

对应的方法定义完毕之后,然后再在对应的管理页面添加在线列表,具体如下:

html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

欢迎来到Facelook

登录列表

Map map = (Map)application.getAttribute("loginUserMap");

out.println("目前共有"+map.size()+"个用户在线!!");

%>

 m : map.entrySet()){%>

">

')">强制退出

好了启动部署项目,然后启动服务,进入在线用户管理模块,简单效果如下图:

d43dd9a2111a0cf3c07fdb385d3557ec.png

需要注意的是:当前登录用户 不允许强制退出自己的登录信息。

这样子,基本上可以实现防止多用户登录的案例了!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值