1.最近今天发现大量用户登录的时候莫名的登陆到别人的帐号,产生的原因是因为网络使用代理服务器了,在过滤器里加个网页过期时间吧,能部分解决这个问题
基本解决方法

((HttpServletResponse)response).setHeader("Pragma", "no-cache"); 

 ((HttpServletResponse)response).setHeader("Cache-Control", "no-cache"); 

 ((HttpServletResponse)response).setDateHeader("Expires", 0L); 

 chain.doFilter(request, response);


但是有的时候不能完全解决,还有一种可能是是session重置的时候没有清空,使用
session.clear();会大量的解决此问题

2. 另外在js中使用模态对话框的时候注意缓存问题,不然就有可能产生类似于串session的现象:
通过ShowModalDialog打开的页面会自动从IE的缓存中获得内容并显示。
如果想每次通过ShowModalDialog打开的页面都自动刷新的话,只需要在脚本
中设定一个参数,例如:
ShowModalDialog("xxx.aspx?id=1&tempid=223");
其中tempid是一个xxx.aspx中并不需要使用到的参数,只要这个参数每次不同,
通过ShowModalDialog打开的页面就都会自动刷新。

知道了session混乱产生的原因之后,也就知道了问题的根源。同时也引出了很多的问题:

1、如何记录住在线人员(这里只有帐号的系统用户,不包括访客);

2、如何限制同一个帐号在同一时间段内只能够登陆一次系统?

3、如何限制不同的用户在同一台机器上登陆系统?

4、管理员如何踢人?

我们首先来分析上面的问题:

首先在服务器端当用户通过身份验证成功登陆系统之后,我们将此用户的信息记录住(OnLineUserManager.java),包括帐号、登陆日期、机器的IP地址、session的ID,session对象。(记住session的ID极其重要,因为服务器识别session是根据id,只要id相同,服务器就认为是同一个用户);

(上面解决了问题1)

这样当用户登陆系统的时候我们首先根据帐号判断用户是否登陆了,如果已经登陆,提示用户;(这样就解决了问题2)

如果未登陆,判断用户的session的id是否已经在用户的信息OnLineUserManager里面了,如果是提示用户

关闭当前窗口,重新点击IE打开一个新的浏览器窗口。(这样session就不会混乱了)。

如果要限制不同的用户在同一台机器上登陆系统?这个就要根据IP地址来判断了。如果OnLineUserManager中

有通过这个机器登陆系统的用户,那么就提示用户同一台机器只能够一个帐号登陆;

(问题3也就解决了,注意:如果用户使用了代理服务器,那么此方法失效。这个方法适用于管理规范的用户,客户在局域网内使用,每个客户有固定的ip。)

问题4如何踢人?你想想OnLineUserManager中记录了用户session对象,只要根据用户的帐号找到对应的

session对象,然后session.invalidate();这样就可以彻底的将捣乱的人提出系统了。


解决IE8测试时session共享问题:
1、在IE8的快捷方式的目标栏中添加-nomerge,再打开IE时就不会共享同一个session了。


2、使用命令行参数 iexplore.exe -nomerge 来打开IE。


关于浏览器的session的问题,有2种情况,IE系列,所有tab不共用一个session,除非是继承tab【通过ctrl+n打开的新窗口】;FF等所有tab共用一个session。此外服务器端判定一个请求是否是新请求,是否需要创建新session可以通过ip来决定,也就是说可以通过IP欺骗来达到每一个虚拟用户请求都会得到不同的session



===============需要注意的是OnLineUserManager必须是线程安全的=我的实现如下==============

[java] view plaincopy 

package com.work.qxgl.login; 




import java.util.Vector; 




import org.apache.commons.logging.Log; 


import org.apache.commons.logging.LogFactory; 




import com.work.util.DateUtil; 




/** 


 * 统计在线用户数。前提是登录的时候限制一个用户只能够在系统中登录一次。 有了这个功能,管理员就可以管理在线用户,如果谁不服从管理,就可以从系统中踢出去。 


 * TODO 将jsp放到WEB-INF后面,然后所有的URL必须通过struts的action调用。 使用拦截器Interceptor来实现权限的控制! 


 * 或者通过web中的Filter来实现权限控制! 实现权限管理系统日志的记录! 


 * 


 * @author wangmingjie 


 * 


 */ 


public class OnLineUserManager { 


 private static Log log = LogFactory.getLog(OnLineUserManager.class); 


 private Vector<OnLineUser> users = null; 






 private OnLineUserManager() { 


 users = new Vector<OnLineUser>();//在构造函数中初始化 


 } 




 static class SingletonHolder { 


 static OnLineUserManager instance = new OnLineUserManager(); 


 } 




 /** 


 * 单例模式。这样简单而且能够保证线程安全。 


 * 


 * @return 


 */ 


 public static OnLineUserManager getInstance() { 


 return SingletonHolder.instance; 


 } 




 /** 


 * 获取到登录用户的数量。 


 * 


 * @return 


 */ 


 public synchronized int getCount() { 


 users.trimToSize(); 


 return users.capacity(); 


 } 




 /** 


 * 通过用户帐号判断该用户是否存在! 必须保证是线程安全的。 


 * 


 * @param userAccount 


 * @return 


 */ 


 public synchronized boolean existUser(String userAccount) { 


 users.trimToSize(); 


 boolean existUser = false; 


 for (int i = 0; i < users.capacity(); i++) { 


 if (userAccount.equals(((OnLineUser) users.get(i)).getUserAccount())) { 


 existUser = true; 


 break; 


 } 


 } 


 return existUser; 


 } 




 /** 


 * @param sessionid 


 * @return 


 */ 


 public synchronized boolean existSession(String sessionid) { 


 users.trimToSize(); 


 boolean existUser = false; 


 for (int i = 0; i < users.capacity(); i++) { 


 if (sessionid.equals(((OnLineUser) users.get(i)).getSessionId())) { 


 existUser = true; 


 break; 


 } 


 } 


 return existUser; 


 } 






 /** 


 * 删除用户 


 * 


 * @param userAccount 


 * @return 


 */ 


 public synchronized boolean deleteUser(String userAccount) { 


 users.trimToSize(); 


 if (existUser(userAccount)) { 


 int currUserIndex = -1; 


 for (int i = 0; i < users.capacity(); i++) { 


 if (userAccount.equals(((OnLineUser) users.get(i)).getUserAccount())) { 


 currUserIndex = i; 


 break; 


 } 


 } 


 if (currUserIndex != -1) { 


 users.remove(currUserIndex); 


 users.trimToSize(); 


 log.debug("用户" + userAccount + "退出系统" 


 + DateUtil.getCurrentDateTime()); 


 log.debug("在线用户数为:" + getCount()); 


 return true; 


 } 


 } 


 return false; 


 } 




 /** 


 * 根据用户帐号,获取在线用户信息 


 * @param userAccount 


 * @return 


 */ 


 public synchronized OnLineUser getUser(String userAccount) { 


 users.trimToSize(); 


 if (existUser(userAccount)) { 


 int currUserIndex = -1; 


 for (int i = 0; i < users.capacity(); i++) { 


 if (userAccount.equals(((OnLineUser) users.get(i)).getUserAccount())) { 


 currUserIndex = i; 


 break; 


 } 


 } 


 if (currUserIndex != -1) { 


 return users.get(currUserIndex); 


 } 


 } 


 return null; 


 } 




 /** 


 * 获取到在线用户的信息。 


 * 


 * @return 


 */ 


 public synchronized Vector<OnLineUser> getOnLineUser() { 


 return users; 


 } 




 public synchronized void addUser(OnLineUser onLineUser) { 


 users.trimToSize(); 


 if (!existUser(onLineUser.getUserAccount())) { 


 users.add(onLineUser); 


 log.debug(onLineUser.getUserAccount() + "/t登录到系统/t" + DateUtil.getCurrentDateTime()); 


 // 通过request才能够获取到用户的ip等信息 


 } else { 


 log.debug(onLineUser.getUserAccount() + "已经存在"); 


 } 


 log.debug("在线用户数为:" + getCount()); 


 } 




} 





 ==================OnLineUser.java============================ 


[java] view plaincopy 

package com.work.qxgl.login; 




import java.io.Serializable; 




import javax.servlet.http.HttpSession; 




/** 


 * @author wangmingjie 


 * @date 2008-6-30下午04:56:37 


 */ 


public class OnLineUser implements Serializable { 




 /** 


 * 


 */ 


 private static final long serialVersionUID = 5461473880667036331L; 




 private String userId; //用户id 


 private String userAccount; //用户帐号 


 private String userName; //用户名称 




 private String loginTime; //登陆时间戳 




 private String sessionId; //session的ID 


 private String userIp ;//ip地址 




 private HttpSession session; //记住session对象,测试能否用来将人员踢出系统 






 public String getUserId() { 


 return userId; 


 } 




 public void setUserId(String userId) { 


 this.userId = userId; 


 } 




 public String getUserAccount() { 


 return userAccount; 


 } 




 public void setUserAccount(String userAccount) { 


 this.userAccount = userAccount; 


 } 




 public String getUserName() { 


 return userName; 


 } 




 public void setUserName(String userName) { 


 this.userName = userName; 


 } 




 public String getSessionId() { 


 return sessionId; 


 } 




 public void setSessionId(String sessionId) { 


 this.sessionId = sessionId; 


 } 




 public String getUserIp() { 


 return userIp; 


 } 




 public void setUserIp(String userIp) { 


 this.userIp = userIp; 


 } 




 public HttpSession getSession() { 


 return session; 


 } 




 public void setSession(HttpSession session) { 


 this.session = session; 


 } 




 public String getLoginTime() { 


 return loginTime; 


 } 




 public void setLoginTime(String loginTime) { 


 this.loginTime = loginTime; 


 } 


 public String toString(){ 


 return "OnLineUser{userId="+userId+",userAccount="+userAccount 


 +",userName"+userName+",loginTime="+loginTime+",userIp="+userIp+",sessionId="+sessionId+"}"; 


 } 




 //===============下面的数据只有在系统登陆日期中记录================================== 


// private String logoutTime;//退出时间戳; 


// private String logoutType;//退出方式 “session超时退出”;“1主动退出” 


// private String lastAccessedTime;// 最后访问时间 




} 



控制一个用户多次登录,当session有效时,如果相同用户登录,就提示已经登录了,当session失效后,就可以不用提示,直接登录了。 


那么如何在session失效后,进行一系列的操作呢? 


这里就需要用到监听器了,即当session因为各种原因失效后,监听器就可以监听到,然后执行监听器中定义好的程序就可以了。 


监听器类为:HttpSessionListener类,有sessionCreated和sessionDestroyed两个方法 


自己可以继承这个类,然后分别实现。 


sessionCreated指在session创建时执行的方法 


sessionDestroyed指在session失效时执行的方法 


给一个简单的例子: 


public class SessionListener implements HttpSessionListener{ 

public void sessionCreated(HttpSessionEvent event) { 

HttpSession ses = event.getSession(); 

String id=ses.getId()+ses.getCreationTime(); 

SummerConstant.UserMap.put(id, Boolean.TRUE); //添加用户 

} 

public void sessionDestroyed(HttpSessionEvent event) { 

HttpSession ses = event.getSession(); 

String id=ses.getId()+ses.getCreationTime(); 

synchronized (this) { 

SummerConstant.USERNUM--; //用户数减一 

SummerConstant.UserMap.remove(id); //从用户组中移除掉,用户组为一个map 

} 

} 

} 

然后只需要把这个监听器在web.xml中声明就可以了 


<listener> 

<listener-class> 

com.demo.SessionListener 

</listener-class> 

</listener>