【问题标题】:Session Handling Issue(To update DB row) - Session closes along with browser会话处理问题(更新数据库行) - 会话与浏览器一起关闭
【发布时间】:2013-01-28 19:41:51
【问题描述】:

我正在使用数据库来存储用户详细信息,包括用户名和密码。它还有一个Security_check 列,默认为“logged_out”。

每当用户登录时,我都会从我验证用户(servlet)的页面中将Security_check 值修改为“logged_in”。每当用户点击注销按钮时,我都会明确地将Security_check 更改为其默认值。

但是当用户在没有退出的情况下关闭浏览器时,就会出现一个大问题,因为该用户的Security_check 列值仍然是“logged_in”,之后当该用户厌倦登录时,他们会得到一个错误消息指出您已经登录(因为我在允许任何用户登录之前检查了Security_check,在这种情况下他们已经登录)。所以他无法登录,也无法注销,因为当他关闭浏览器时会话已过期。那我该怎么办?

下面是 HttpSessionListener 类的代码,它不起作用:

package com.svc.session;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.sql.*;
import javax.servlet.http.HttpSession;


public class Session_Invalidator implements HttpSessionListener
{
    public Session_Invalidator()
    {
        try    
        {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        }
        catch(Exception e) 
        {
        }
    }

    public void sessionCreated(HttpSessionEvent se)
    {
    }

    public void sessionDestroyed(HttpSessionEvent se)    
    {
        HttpSession session = se.getSession();
        String uName = session.getAttribute("userName").toString().trim();

        Connection con = null;
        PreparedStatement stmt = null;

        try 
        {
            // i am using a space between the colon and odbc because if 
            // I don't it will be converted to smile, so ignore the space
            con = DriverManager.getConnection("jdbc: odbc:CMS","","");
            stmt = con.prepareStatement("update Users set security_check=default where     login_name=?");
            stmt.setString(1, uName);
            int no = stmt.executeUpdate();
        } catch(Exception e) 
        {
        }
    }
}

【问题讨论】:

  • 请更具体地告诉我们,究竟是什么不起作用。你调试过你的代码吗?当会话停用时,方法sessionDestroyed() 是否被调用?有什么例外吗?如果您单独调用它,您的数据库访问代码是否有效?独立地,如果没有明确的注销,我认为禁止重新登录不是一个好主意。即使您在会话停用时自动注销有效,用户也必须等待自动会话超时(通常为 20 到 30 分钟)。
  • 一切正常,但是当我关闭浏览器时,db(也是 sessiondestroyed)没有调用。但它像往常一样在默认会话到期时间之后调用。但在此期间用户无法登录(因为数据库中的 security_check 已登录),所以我如何在浏览器关闭/系统突然关闭后尽快更新
  • 这是正常行为。服务器永远不会知道用户是关闭浏览器还是只是在厨房喝咖啡。因此,服务器将保持会话打开,直到用户返回并继续工作的情况下超时。因此,sessionDestroyed() 方法总是在会话超时时调用,而不是在浏览器关闭时调用。

标签: java jsp session servlets session-timeout


【解决方案1】:

它认为你有两种选择。

  1. 选择一个非常短的会话超时时间(例如一两分钟)并使用 AJAX 调用实现从您的网页到服务器的 ping 之类的操作。因此,当用户浏览器打开并显示您的网页时,您的服务器将始终收到 ping 通知并保持会话打开。如果用户关闭浏览器,您的服务器会话将很快超时。但仍有短暂的延迟。这种方法的缺点是你会产生更多的流量并且你必须找到一个合适的会话超时值。如果存在一些网络延迟,太短的值可能会导致会话超时。过长的值会增加用户无法重新登录的时间。

  2. 这是我最喜欢的解决方案:不要被限制到根本不允许重新登录。不要将登录状态存储在数据库中。如果用户想在关闭浏览器后重新登录,则会创建一个新的服务器端会话,并且用户提供登录凭据,这很好。旧会话将在超时后被销毁。如果您使用基于容器的安全性,这是默认行为。我建议使用基于容器的安全性 (JAAS)。为什么要禁止重新登录?

以下是一些关于 JAAS 的链接:

【讨论】:

  • 我明白了...为什么我在数据库中存储登录详细信息是为了显示“在线用户”,基于该行我能够显示在线用户..还有其他方法可以显示在线用户非常
  • 您可以在应用程序范围内保存一个包含所有在线用户的集合(或者如果您对在线用户的数量感兴趣,可以使用一个整数),并使用您的会话侦听器来更新该集合/整数。但要小心同步对全局值的访问。最简单的情况是只计算活动会话。也许这对您的用例来说已经足够了。如果您想知道谁在线,您必须特别对待重新登录。但无法解决原来的问题。在会话超时之前,您永远不会知道用户何时关闭浏览器。
【解决方案2】:

我有一个解决方法来解决这个问题,就是使用一个全局对象将 sessionId 和用户 ID 一起存储,当会话超时时,我们可以从会话销毁事件中获取 sessionId,然后我们可以通过 sessionId 获取用户 ID。 请查看我的博客:Update DB's User status when Session timeout

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-03
    • 2023-03-21
    • 2011-06-03
    • 1970-01-01
    • 2012-11-13
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多