隨筆 - 100  文章 - 50  trackbacks - 0
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          我收藏的一些文章!

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          在web應(yīng)用系統(tǒng)中,出于安全性考慮,經(jīng)常需要對(duì)同一客戶端登錄的用戶數(shù)量和一個(gè)客戶同時(shí)在多個(gè)客戶端登陸進(jìn)行限制。具體一點(diǎn)就是:

              1、在同一臺(tái)電腦上一次只允許有一個(gè)用戶登錄系統(tǒng),2、一個(gè)用戶在同一時(shí)間只允許在一個(gè)客戶端登錄。

              我最近做的一個(gè)系統(tǒng)就遇到了這樣的問題,本來系統(tǒng)已經(jīng)開發(fā)完成了,但是安全測(cè)評(píng)沒有通過,就是因?yàn)闆]有做這兩個(gè)限制。怎么來做這樣的限制呢?我在網(wǎng)上找了很久,發(fā)現(xiàn)問這個(gè)問題的人很多,但是沒有找到特別清楚的答案。后來自己摸索著,看了一些書,終于找到解決辦法了。

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

              先介紹一下我那個(gè)系統(tǒng)的背景:j2ee,tomcat,沒有用cookie。

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

              1、要解決同一臺(tái)電腦上只允許有一個(gè)用戶登錄系統(tǒng),只有一個(gè)辦法。監(jiān)視每一個(gè)連接的來源,如果發(fā)現(xiàn)有一個(gè)新的連接與某個(gè)已經(jīng)存在的連接來自同一臺(tái)電腦,則終止其中的一個(gè)(當(dāng)然,也可以提醒用戶,讓他自己決定終止哪一個(gè))。

              2、要禁止一個(gè)用戶賬號(hào)同時(shí)在不同的客戶端登錄,只有監(jiān)視每一個(gè)連接的用戶賬號(hào),如果發(fā)現(xiàn)一個(gè)新連接的用戶賬號(hào)跟某個(gè)已經(jīng)存在的連接的用戶賬號(hào)相同,則自動(dòng)將前一個(gè)終止(同樣,也可以讓用戶自己決定終止哪一個(gè))。

           

              確定了基本思路以后,就要找具體辦法了。我最初的想法是在數(shù)據(jù)庫建立一張表,存放已登錄用戶的用戶名、物理地址、Session id等信息。當(dāng)用戶登錄時(shí),與這張表里面的數(shù)據(jù)進(jìn)行匹配,如果發(fā)現(xiàn)物理地址與表中的某條記錄相同,則表示是同一臺(tái)客戶端上有多個(gè)用戶再登錄,如果發(fā)現(xiàn)正在登錄的用戶的用戶名與表中已有記錄相同而主機(jī)名不同,則表示是一個(gè)賬號(hào)同時(shí)在不同的客戶端使用。

              相信很多一開始遇到這個(gè)問題的人都會(huì)考慮這種解決辦法。但是這種辦法有很多問題,最主要的問題有兩個(gè):第一是效率,每一次都要從數(shù)據(jù)庫里面取數(shù)據(jù)進(jìn)行匹配。第二是用戶退出時(shí)需要?jiǎng)h除表中的記錄,而當(dāng)用戶非正常退出時(shí),很難及時(shí)監(jiān)測(cè)(后來發(fā)現(xiàn)其實(shí)有辦法監(jiān)測(cè))。

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

           

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

          監(jiān)聽器可以監(jiān)聽Session及其所包含的屬性,即Attribute。

          所以我們要做的就是:

          1、建立一個(gè)監(jiān)聽器,實(shí)現(xiàn)HttpSessionAttributeListener接口,監(jiān)聽每一個(gè)Attribute的增加、編輯、刪除事件。監(jiān)聽器中還要建立一個(gè)map,將所有的session放入這個(gè)map中。

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

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

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

           

          Web.xml文件:

          <listener>

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

          </listener>

           

          用戶登錄地址數(shù)據(jù)傳輸對(duì)象:

          public class UserSessionAdd {

             

              private String add;

             

              private String sessid;

             

              private String username

           

              public String getUsername(){

                 return username

              }

              Public void setUsername(String username){

                 this.username=username;

              }

              public String getIp() {

                 return add;

              }

              public void setAdd(String add) {

                 this.add = add;

              }

              public String getSessid() {

                 return sessid;

              }

              public void setSessid(String sessid) {

                 this.sessid = sessid;

              }

             

          }

           

          用戶登錄的代碼:

          ···

          String userHost = request.getRemoteHost();

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

          UserSessionAdd usa = new UserSessionAdd();

          usa.setUsername(username);

          usa.setSessid(sessionId);

          usa.setAdd(userHost);

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

           

           

          監(jiān)聽器代碼:

          public class MyListener implements HttpSessionAttributeListener{

             

              Map<String, HttpSession> map = new HashMap<String, HttpSession>();

              public void attributeAdded(HttpSessionBindingEvent event) {

                 String name = event.getName();

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

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

                     if(map.get(usa.getAdd())!=null){

                        HttpSession sess = map.get(usa.getAdd());

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

                        sess.removeAttribute("usa");

                        sess.invalidate();

                     }

                     map.put(usa.getAdd(), event.getSession());

                 }

              }

           

              public void attributeRemoved(HttpSessionBindingEvent event) {

                 String name = event.getName();

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

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

                     map.remove(usa.getAdd());

                 }

              }

           

              public void attributeReplaced(HttpSessionBindingEvent event) {

                 // TODO Auto-generated method stub

                 ````

              }

          }

           

          本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/yutan_313/archive/2010/03/22/5405934.aspx

          posted on 2010-06-10 10:27 fly 閱讀(1637) 評(píng)論(0)  編輯  收藏 所屬分類: jsp學(xué)習(xí)
          主站蜘蛛池模板: 绥芬河市| 遵义县| 胶南市| 临西县| 龙井市| 平果县| 玉环县| 城口县| 新疆| 宜川县| 闸北区| 聊城市| 鄂温| 天镇县| 齐河县| 嘉鱼县| 婺源县| 太康县| 镇平县| 兴山县| 安泽县| 涿鹿县| 剑阁县| 新郑市| 阳高县| 楚雄市| 垦利县| 长治市| 拉萨市| 石柱| 花垣县| 乌苏市| 泗阳县| 长武县| 通州市| 南城县| 梅州市| 云龙县| 泽库县| 阜康市| 元朗区|