如何防止同一账号多次登录

如何限制同一客户端登录的用户数量以及禁止同一用户同时在不同客户端登录:

首先确定解决这两个问题的基本思路:

    1、要解决同一台电脑上只允许有一个用户登录系统,只有一个办法。监视每一个连接的来源,如果发现有一个新的连接与某个已经存在的连接来自同一台电脑,则终止其中的一个(当然,也可以提醒用户,让他自己决定终止哪一个)。

    2、要禁止一个用户账号同时在不同的客户端登录,只有监视每一个连接的用户账号,如果发现一个新连接的用户账号跟某个已经存在的连接的用户账号相同,则自动将前一个终止(同样,也可以让用户自己决定终止哪一个)。

常见3种解决办法:

1)通过数据库状态位判断该用户是否已经登录。

       首先在数据库建立一张表,存放已登录用户的用户名、物理地址、Session id等信息。当用户登录时,与这张表里面的数据进行匹配,如果发现物理地址与表中的某条记录相同,则表示是同一台客户端上有多个用户再登录,如果发现正在登录的用户的用户名与表中已有记录相同而主机名不同,则表示是一个账号同时在不同的客户端使用。

    相信很多一开始遇到这个问题的人都会考虑这种解决办法。但是这种办法有很多问题,最主要的问题有两个:第一是效率,每一次都要从数据库里面取数据进行匹配。第二是用户退出时需要删除表中的记录,而当用户非正常退出时,很难及时监测(后来发现其实有办法监测)。

2)利用缓存Cache方便地实现此功能

       Cache与Session这二个状态对像的其中有一个不同之处,Cache是一个全局对象,作用的范围是整个应用程序,所有用户;
而Session是一个用户会话对象,是局部对象,用于保存单个用户的信息。 
只要把每次用户登录后的用户信息存储在Cache中,把Cache的Key名设为用户的登录名,Cache的过期时间设置为Session的超时时间,在用户每次登录的时候去判断一下Cache[用户名]是否有值,如果没有值,证明该用户没有登录,否则该用户已登录。

/// <summary>
/// 防止多次登录
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>

private void Button1_Click(object sender, System.EventArgs e)
{
string strUser = string.Empty;
string strCacheKey = this.TextBox1.Text;
 
strUser = Convert.ToString(Cache[strCacheKey]);
 
if (strUser == string.Empty)
{
TimeSpan SessTimeOut = new TimeSpan(0, 0, System.Web.HttpContext.Current.Session.Timeout, 0, 0);
 
Cache.Insert(strCacheKey, strCacheKey, null, DateTime.MaxValue, SessTimeOut, CacheItemPriority.NotRemovable, null);
Session["User"] = strCacheKey;
this.Label1.Text = Session["User"].ToString();
}
else
{
this.Label1.Text = "这个用户已经登录!";
}
}

3)利用session监听器监听每一个登录用户的登录情况。

简洁版方法(c# 框架):

监听器可以监听Session及其所包含的属性,即Attribute。

A.用户登录后,先去数据库查询该登录名是否存在、是否锁定。

       在登录名存在且非锁定的情况下,从application内置作用域对象中取出所有的登录信息,查看该登录名是否已经登录,如果登录了,就友好提示下;反之表示可以登录,将该登录信息保存在application中。

主要代码如下:


//所有的登录信息
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(user.getFuUserName()) || loginUserMap.containsValue(sessionId)){
continue;
}
isExist = true;
break;
}
if(isExist){
//该用户已登录
//
}else {
//该用户没有登录
loginUserMap.put(result.getFuUserName(), sessionId);
//
}
//

B.登录考虑完之后,考虑退出。
      用户正常退出时,我们需要将该用户的登录信息从session中移除。我们可以写一个Session监听器,监听sessioon销毁的时候,我们将登录的用户注销掉,也就是从application中移除。表示该用户已经下线了。

//
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); 
  } 
  //
} 
//

C.登录的用户突然关闭了浏览器,未点击退出按钮,情况,虑退出。

那么可以利用beforeunload 事件,在浏览器刷新或者关闭的时候触发。

//在刷新或关闭时调用的事件
$(window).bind('beforeunload',function(){
 $.ajax({
  url:"${ctx}/system/user/user!logout.action",
  type:"post",
  success:function(){
   alert("您已退出登录");
  }
 });
});

完整版方法(Java ee 开发框架):

1 ) 在登录方法中加入如下两行语句,作为程序的入口:


SessionListener.isAlreadyEnter(getHttpRequest().getSession(),this.getUserCode(),loginUser);  
getHttpRequest().getSession().setAttribute("isLoginIn", "LoginIn");  

2)在SessionListener类中做相关的踢出处理:

import java.util.HashMap;  
import java.util.Iterator;  
import java.util.Map;  
import javax.servlet.ServletRequestEvent;  
import javax.servlet.ServletRequestListener;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpSession;  
import javax.servlet.http.HttpSessionAttributeListener;  
import javax.servlet.http.HttpSessionBindingEvent;  
import javax.servlet.http.HttpSessionEvent;  
import javax.servlet.http.HttpSessionListener;  
import org.apache.struts2.ServletActionContext;  
import com.hhwy.iepip.framework.message.Message;  
import com.opensymphony.xwork2.ActionContext;  
    
public class SessionListener implements HttpSessionListener,ServletRequestListener,HttpSessionAttributeListener{    
    public static Map<String, HttpSession> sessionMap = new HashMap<String, HttpSession>();  
    public static Map<String, HttpSession> sessionMap1 = new HashMap<String, HttpSession>();  
    private static Boolean onlyOne = Boolean.valueOf(Message.getMessage("session.onlyone"));  
    private HttpServletRequest request ;  
      
    //获取request对象 
    public void requestInitialized(ServletRequestEvent event) {  
        request = (HttpServletRequest)event.getServletRequest();  
    }                      
      
    //以下是实现HttpSessionListener中的方法:该方法登录与否都会执行   
    public void sessionCreated(HttpSessionEvent se){  
    }  
      
    //以下是实现HttpSessionListener中的方法   
    public void sessionDestroyed(HttpSessionEvent se){    
        hUserName.remove(se.getSession().getId());  
        UserObject.remove(se.getSession().getId());  
        if(sessionMap!=null){  
            sessionMap.remove(se.getSession().getId());  
        }  
        if(sessionMap1!=null){  
            sessionMap1.remove(se.getSession().getId());  
        }  
    }     
    /**    
      * isAlreadyEnter-用于判断用户是否已经登录以及相应的处理方法    
      * <该方法是系统业务的方法,不是处理单个用户登录的问题,以该方法做为程序的入口> 
      */     
    public static boolean isAlreadyEnter(HttpSession session,String sUserName,LoginUserInfo loginTriggers){     
        boolean flag = false;     
        return flag;     
    }     
  
     /** 
      * 此方法,可以在登录时候添加一个session 用以判断是否已经登录,然后再进行登录人登录控制 
      */  
    public void attributeAdded(HttpSessionBindingEvent event) {  
    //如果只允许一个账号一处登陆,单台客户端电脑只允许一个用户登录  
        if(onlyOne.booleanValue()){  
            String name = event.getName();  
            if(name.equals("isLoginIn")){                 
            // 单台客户端电脑只允许一个用户登录  
            String ipAddr = this.getIpAddr(request);             
            //如果原先已登录,则踢出原先登陆的         
            if(sessionMap1.containsKey(ipAddr) ){  
                try{        
                sessionMap1.get(ipAddr).invalidate();  
                }catch(Exception e){}  
                sessionMap1.remove(ipAddr);  
                }       
            if(ipAddr != null  && event.getSession().isNew())  
                sessionMap1.put(ipAddr, event.getSession());  
                  
            //只允许一个账号一个客户端登陆  
            String userName= getUserName(event);         
            if(sessionMap.containsKey(userName) ){  
                try{  
                sessionMap.get(userName).invalidate();  
                }catch(Exception e){}  
                sessionMap.remove(userName);  
                }  
                if(userName != null  && event.getSession().isNew())  
                     sessionMap.put(userName, event.getSession());      
            }  
        }  
    }  
  
    public static String getIpAddr(HttpServletRequest request) {  
    String ip = request.getHeader("x-forwarded-for");  
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
        ip = request.getHeader("Proxy-Client-IP");  
    }          
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
        ip = request.getHeader("WL-Proxy-Client-IP");  
    }  
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
        ip = request.getRemoteAddr();  
    }  
    return ip;                  
    }    
      
    //获取session中存储的用户名
    private String getUserName(HttpSessionBindingEvent se) {  
    String userName = null;  
    return userName;  
    }  
      
    public void attributeRemoved(HttpSessionBindingEvent event) {  
    // TODO Auto-generated method stub  
    }  
  
    public void attributeReplaced(HttpSessionBindingEvent arg0) {  
    // TODO Auto-generated method stub  
    }  
      
    public void requestDestroyed(ServletRequestEvent arg0) {  
    // TODO Auto-generated method stub  
    }  
}     

 

转载于:https://my.oschina.net/u/3544533/blog/1796623

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值