如何限制同一用戶同時在不同客戶端登錄?


如何限制同一用戶同時在不同客戶端登錄?

轉自:《如何限制同一客戶端登錄的用戶數量以及禁止同一用戶同時在不同客戶端登錄?》


    在web應用系統中,出於安全性考慮,經常需要對同一客戶端登錄的用戶數量和一個客戶同時在多個客戶端登陸進行限制。具體一點就是:

    1、在同一台電腦上一次只允許有一個用戶登錄系統,2、一個用戶在同一時間只允許在一個客戶端登錄。

    我最近做的一個系統就遇到了這樣的問題,本來系統已經開發完成了,但是安全測評沒有通過,就是因為沒有做這兩個限制。怎么來做這樣的限制呢?我在網上找了很久,發現問這個問題的人很多,但是沒有找到特別清楚的答案。后來自己摸索着,看了一些書,終於找到解決辦法了。

    要解決這個問題實際上不難,對於高手來說可能都懶得去說了,但是對於不熟悉web編程的人來說可能會困擾很久。下面我把我的解決辦法說出來,供大家參考!

    先介紹一下我那個系統的背景:j2ee,tomcat,沒有用cookie。

    首先確定解決這兩個問題的基本思路:

    1、要解決同一台電腦上只允許有一個用戶登錄系統,只有一個辦法。監視每一個連接的來源,如果發現有一個新的連接與某個已經存在的連接來自同一台電腦,則終止其中的一個(當然,也可以提醒用戶,讓他自己決定終止哪一個)。

    2、要禁止一個用戶賬號同時在不同的客戶端登錄,只有監視每一個連接的用戶賬號,如果發現一個新連接的用戶賬號跟某個已經存在的連接的用戶賬號相同,則自動將前一個終止(同樣,也可以讓用戶自己決定終止哪一個)。

 

    確定了基本思路以后,就要找具體辦法了。我最初的想法是在數據庫建立一張表,存放已登錄用戶的用戶名、物理地址、Session id等信息。當用戶登錄時,與這張表里面的數據進行匹配,如果發現物理地址與表中的某條記錄相同,則表示是同一台客戶端上有多個用戶再登錄,如果發現正在登錄的用戶的用戶名與表中已有記錄相同而主機名不同,則表示是一個賬號同時在不同的客戶端使用。

    相信很多一開始遇到這個問題的人都會考慮這種解決辦法。但是這種辦法有很多問題,最主要的問題有兩個:第一是效率,每一次都要從數據庫里面取數據進行匹配。第二是用戶退出時需要刪除表中的記錄,而當用戶非正常退出時,很難及時監測(后來發現其實有辦法監測)。

    后來在網上的某個帖子里面看到一位大俠提到用監聽器,只是那位大俠說的太含糊,照他說的辦法根本無法解決。雖然無法解決,但是提供了一個思路。於是我找了一本書,仔細看了其中關於監聽器的部分。解決辦法就在其中了!!!

 

    監聽器的詳細介紹見我的下一篇博文,這里先把解決辦法告訴大家:

監聽器可以監聽Session及其所包含的屬性,即Attribute。

所以我們要做的就是:

1、建立一個監聽器,實現HttpSessionAttributeListener接口,監聽每一個Attribute的增加、編輯、刪除事件。監聽器中還要建立一個map,將所有的session放入這個map中。

2、在用戶登錄時將用戶名、物理地址、Session id存到Session中去(可以建立一個用戶登錄地址數據傳輸對象,我建立了一個UserSessionAdd類,里面包含username,macAdd,sessionId三個屬性,用戶登錄時將這個數據對象初始化,並存入到session中)。

3、每個新會話開啟時,在監聽器中對Session包含的屬性進行判斷,如果新增的屬性與map中已有session的用戶登錄地址數據相同,則表示新會話與我們要做的兩個限制相沖突。將與之沖突的會話提取出來,銷毀掉!

這么說,還是不夠清楚,下面看代碼:

 

Web.xml文件:

<listener>

       <listener-class>監聽器類的路徑,如:com.web.MyListener</ listener-class >

</listener>


用戶登錄地址數據傳輸對象:

public class UserSessionAdd {

    private String addHost;//主機
    private String sessid; //會話窗口Id
    private String username;//用戶名
    private Integer userId;  //用戶Id

    public String getUsername(){
       return username;
    }

    public void setUsername(String username){
       this.username=username;
    }

    public String getAddHost() {
       return addHost;
    }

    public void setAddHost(String addHost) {
       this.addHost = addHost;
    }

    public String getSessid() {
       return sessid;
    }

    public void setSessid(String sessid) {
       this.sessid = sessid;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }
}

用戶登錄的代碼:

String userHost = request.getRemoteHost();

String sessionId = request.getSession().getId();

UserSessionAdd usa = new UserSessionAdd();

usa.setUserId(userId);

usa.setUsername(username);

usa.setSessid(sessionId);

usa.setAddHost(userHost);

request.getSession().setAttribute(“usa”,usa);


監聽器代碼:

public class MyListener implements HttpSessionAttributeListener{

    Map<Integer, HttpSession> map = new HashMap<Integer, HttpSession>();//將所有的登錄的session放入這個map中

    public void attributeAdded(HttpSessionBindingEvent event) {

       String name = event.getName();//session中保存的對象名

       if(name.equals("usa")){

           UserSessionAdd usa = (UserSessionAdd)event.getValue();//獲取“最新的”當前登錄用戶的主機地址和會話窗口數據傳輸對象

           if(map.get(usa.getUserId())!=null){//map中存在當前登錄用戶的id

              HttpSession sess = map.get(usa.getUserId());//獲取map中“先前的”保存的當前登錄用戶的會話

              UserSessionAdd usa1 = (UserSessionAdd)sess.getAttribute("usa");

              sess.removeAttribute("usa");//在“先前的”會話窗口中移除當前用戶登錄的數據傳輸對象

              sess.invalidate();//令“先前的”會話窗口失效

           }

           map.put(usa.getUserId(), event.getSession());//將“最新的”當前登錄用戶的主機地址和會話窗口放入map

       }

    }

 

    public void attributeRemoved(HttpSessionBindingEvent event) {

       String name = event.getName();

       if(name.equals("usa")){

           UserSessionAdd usa = (UserSessionAdd)event.getValue();

           map.remove(usa.getUserId());

       }

    }

 

    public void attributeReplaced(HttpSessionBindingEvent event) {

       // TODO Auto-generated method stub

       ````

    }

}
————————————————
原文鏈接:https://blog.csdn.net/yutan_313/java/article/details/5405934


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM