`

<转>session 之session混乱解决方法

    博客分类:
  • JAVA
 
阅读更多
转:http://blog.csdn.net/wmj2003/article/details/2601802


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>  
分享到:
评论

相关推荐

    Discuz! X3.4 简体中文-PHP

    风格管理中新增操作结果混乱的问题&lt;/p&gt;&lt;p&gt;40、修复 IE6、IE7等浏览器提示common.js报错的Bug&lt;/p&gt;&lt;p&gt;41、修复 前台充值卡密页面不显示验证码和同一卡密充值2次成功的Bug&lt;/p&gt;&lt;p&gt;42、【轻量级 PR】:修复门户”模块...

    浏览器多窗口共用session引发的混乱

    NULL 博文链接:https://vearn.iteye.com/blog/376407

    理解PHP中的Session及对Session有效期的控制

     Session的中文译名叫做“会话”,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。目前社会上对session的理解非常混乱:有时候我们...

    教你如何使用php session

    PHP session用法其实很简单它可以把用户提交的数据以全局变量形式保存在一个session中并且会生成一个唯一的session_id,这样就是为了多了不会产生混乱了...如何使用session,凡是与session...

    Session Buddy-crx插件

    非常适合释放内存并避免混乱。 ●崩溃后恢复打开的选项卡。 ●在一处查看和管理所有打开的选项卡。 ●搜索打开的标签和集合,以快速找到所需的内容。 下载此扩展程序即表示您同意在http://bit.ly/IUdYvv上发布的...

    Session Manager-crx插件

    这不仅可以通过减少混乱来提高生产率,而且还可以在系统崩溃时充当自动备份,同时还为其他程序节省了一些急需的资源。 功能:+每个会话最多120个标签+最多30个会话+在所有PC之间自动同步* *请确保使用浏览器供应商的...

    会话伙伴「Session Buddy」-crx插件

    伟大的释放内存,避免混乱。 ●在崩溃后或操作系统重新启动计算机时恢复打开的选项卡。 ●在一个位置管理打开的窗口和标签。 ●按主题组织保存的选项卡。 ●搜索打开和保存的标签,快速找到你要找的。 ●导出适用于...

    session 加入redis的实现代码

    session,中文经常翻译为会话,其本来的含义是 指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话“在 一个浏览器会话期间...

    会话控制「Session Control」-crx插件

    TabMate可帮助您管理选项卡混乱并提高工作效率。存放一组您要保存以供以后使用的选项卡/窗口,并在需要时轻松还原它们。使用快速切换器在打开的选项卡和存储中搜索并切换到它们。拖放选项卡以在窗口或隐藏中重新排列...

    Tab Session Master-crx插件

    使用“轻松”选项卡管理浏览器选项卡和书签Session Master是一个统一的会话管理器和书签管理器。 ●保存打开的选项卡,以后再恢复。 非常适合释放内存并避免混乱。 ●关闭窗口时自动保存●定期自动保存●崩溃或操作...

    Servlet过滤器小实例

    我们完成这个操作可以是在后台逻辑中进行判断,但是这样就会让后台逻辑显得很混乱。比较好也比较常见的方法是用专门的servlet过滤器进行过滤。java中有个Filter类专门从事这类工作,下面以一个简单的实例进行演示: ...

    SecuretCRT 64位绿色破解版

    SecuretCRT 64位绿色破解版 ===================================================... Activator tray的使用大大减少了桌面混乱  Secure Shell将logon和session数据加密  Port forwarding保证了TCP/IP数据的安全

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    互联网系统垂直架构之Session解决方案.mp4 │ │ │ ├─7.分布式框架ZooKeeper之服务注册与订阅 │ │ 7.分布式框架Zookeeper之服务注册与订阅.mp4 │ │ │ ├─8.高性能网络编程必备技能之IO与NIO阻塞分析 │ │...

    关于UEditor编辑器远程图片上传失败的解决办法

    打开后我们先配置 savePath ,因为不同用户使用,需要存放到不同的目录,以免混乱,也方便管理 修改后代码: 复制代码 代码如下: //远程抓取图片配置 if(isset($_SESSION[‘admin’])){ $myPath = ...

    chatgpt实现一个利用chatgpt自动生成wiki词条知识点的小工具,用来整理知识点

    版本:v0.1 bot 模型:official v3 ...本人代码水平极差,格式混乱,但是目前没空调整,所以请见谅 强烈推荐人工二次审核输出页面(而且你自己做的词条不看做了有啥用),某些输出可能需要迭代才能自洽,否则将

    secureCRT工具

    Activator tray的使用大大减少了桌面混乱 Secure Shell将logon和session数据加密 Port forwarding保证了TCP/IP数据的安全 密码和RSA识别 Blowfish, DES, 3DES 和 RC4密码 X11 forwarding 折叠编辑本段v3.4新...

Global site tag (gtag.js) - Google Analytics