我的 Web 应用程序将用户登录和注销记录在数据库表中,以便我们跟踪用户事件。
这在用户显式登录或注销时效果很好,因为底层身份验证代码负责这些日志记录事件。
但是,当用户让计算机闲置 30 分钟时,网络 session 将过期,我们将有一个登录事件而没有相应的注销事件。
我认为解决此问题的唯一策略是在 web.xml 中定义的 30 分钟之前触发一个 javascript 事件,并在 session 到期之前将用户踢出。然而,这有需要 javascript 的局限性,当有人使用多个选项卡时,它可能会产生一些意想不到的结果(即,用户正在使用 tab2,而 session 在 tab1 中已过期)。
对于这种情况,您有什么建议?
最佳答案
您想使用HttpSessionListener
。它是 Servlet 规范为这种情况定义的标准接口(interface)。
注意事项见下文。
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class LogoutListener implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
// NOTE: You need to store some kind of user identification
// in the session. My example just has a "username"
// in here.
String username = session.getAttribute("username");
// If the username is null, there was no logged-in user
// to log-out (e.g. non-authenticated user).
if(null != username) {
// NOTE: Obviously, this needs to call your existing
// "logout"-recording code. Just an example.
MyDBUtilities.registerLogout(username, System.currentTimeMillis());
}
}
@Override
public void sessionCreated(HttpSessionEvent event) {
// Ignore
}
}
如果您使用上面的代码,您会发现未明确注销的用户将获得一条注销记录,而明确注销的用户将获得两条。为什么?因为您可能会使用“注销”操作来写入“注销”记录,然后 session 监听器会立即运行并生成第二个审计条目。
这个问题有两个明显的解决方案:
- 停止在“注销”操作中记录注销事件,让事件处理程序记录所有 注销
- 注销时删除用户的“用户名” session 属性,事件处理程序将忽略该事件
关于session - 记录 Tomcat 过期 session 的策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41259377/