在Java EE中通知用户会话超时

时间:2009-12-31 12:41:49

标签: jsp servlets java-ee session-timeout

我的要求是通过弹出窗口通知用户,说明用户会话即将在x秒内超时,以防用户在网页上执行任何活动。

除此要求外,还要在弹出窗口中动态减少x秒值。

我使用的环境是Java EE。

3 个答案:

答案 0 :(得分:11)

利用HttpSession#getMaxInactiveInterval()setTimeout()。除非您想在每个客户端活动(轮询)上推迟超时,否则不需要Ajax用于此特定目的。

基本示例:

<script>
    var secondsBeforeExpire = ${pageContext.session.maxInactiveInterval};
    var timeToDecide = 15; // Give client 15 seconds to choose.
    setTimeout(function() {
        alert('Your session is about to timeout in ' + timeToDecide + ' seconds!')
    }, (secondsBeforeExpire - timeToDecide) * 1000);
</script>

要神奇地减少消息内部的时间,那么你需要一个带有div的覆盖,而不是基本alert(),你可以通过HTML DOM树控制内容并使用另一个{{1}在1秒内动态更改文本。

请注意,此脚本必须由setTimeout()提供,才能使EL正常工作。因此,您需要将脚本放在JSP页面的HTML JspServlet中,或者如果您确实希望将所有JS放在单独的<head>文件中,那么您需要让{{1处理任何*.js请求。

答案 1 :(得分:1)

我不认为Java / Java EE在这方面会有所帮助,因为这需要在客户端处理(即使用JavaScript)。我能想到的一个解决方案是设置一种在服务器超时前几分钟通知用户的计时器。

在谷歌搜索时,我发现Eric Pascarello的Update User's Session with AJAX博客文章(以及重新加载的版本Updating User Session with Ajax - Round 2)准确描述了这样的解决方案(并使用XMLHttpRequest来更新会话) 。他的Ajax会话管理脚本可用here

答案 2 :(得分:0)

可能是简单的servlet,如果没有完善的客户端逻辑,spring-mvc或spring-security自动注销是不可能的。
考虑到应用程序将同时具有两种类型的请求

  • AJAX和
  • 提交表单/重新加载页面

自动注销需要经过精心计算的逻辑。通过以下

展示我的自动注销功能实现

优势。


1.无需额外的呼叫/请求即可实现此目的。如果活动用户超过1万,并且要实现自动注销的额外呼叫,则要考虑对性能的影响。
2.使用标签进行一线配置。
3.即使用户打开多个选项卡或多个窗口也可以正常工作。
4.它会在会话无效30秒之前提示您,因此,如果您填写了表单但未提交,则可以使会话保持活动状态(一键扩展会话)。因此,用户不太可能丢失未保存的数据。

用法


1。如下所示,在所需的JSP页面中包括自动注销脚本。

    ....
    </body>
    <jsp:include page="../template/autologout-script.jsp"></jsp:include>
</html>

2。创建一个JSP页面autologout-script.jsp并添加以下代码。 注意:无需编辑/配置

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<script>
$(document).ready(function()
{
    var timeOutTimeInSeconds = ${ timeOutTimeInSeconds }; 
    var showTimerTimeInSeconds= ${ showTimerTimeInSeconds };

    var sessionCheckIntervalId = setInterval(redirectToLoginPage, timeOutTimeInSeconds * 1000);
    var timerDisplayIntervalId = setInterval(showTimer, (timeOutTimeInSeconds - showTimerTimeInSeconds) * 1000);
    var badgeTimerId;
    window.localStorage.setItem("AjaxRequestFired", new Date());

    function redirectToLoginPage(){
        //location.href =  '<c:url value="/" />'+'${loginPageUrl}';
        window.location.reload();
    }

    $(document).ajaxComplete(function () {
        resetTimer();
    });

    $(window).bind('storage', function (e) {
         if(e.originalEvent.key == "AjaxRequestFired"){
             console.log("Request sent from another tab, hence resetting timer")
             resetTimer();
         }
    });

    function resetTimer()
    {
        showTimerTimeInSeconds= ${ showTimerTimeInSeconds };

        console.log("timeOutTimeInSeconds : "+timeOutTimeInSeconds)
        window.localStorage.setItem("AjaxRequestFired", new Date());

        window.clearInterval(sessionCheckIntervalId);
        sessionCheckIntervalId = setInterval(redirectToLoginPage, timeOutTimeInSeconds * 1000);

        window.clearInterval(timerDisplayIntervalId);
        timerDisplayIntervalId = setInterval(showTimer, (timeOutTimeInSeconds - showTimerTimeInSeconds) * 1000);

        hideTimer();
    }

    function showTimer()
    {
        $('#sessionTimeRemaining').show();
        $('#sessionTimeRemainingBadge').html(showTimerTimeInSeconds--);
        window.clearInterval(timerDisplayIntervalId);
        badgeTimerId = setInterval(function(){
            $('#sessionTimeRemainingBadge').html(showTimerTimeInSeconds--);
        }, 1000);
    }

    function hideTimer()
    {
        window.clearInterval(badgeTimerId);
        $('#sessionTimeRemaining').hide();
    }
});
</script>

3。配置会话属性以配置超时设置 注意:在会话创建后配置此。您可以实现HttpSessionListener sessionCreated方法,并根据需要设置以下配置。

session.setMaxInactiveInterval(300);

session.setAttribute("timeOutTimeInSeconds", 300);
session.setAttribute("showTimerTimeInSeconds", 30);

4。在html下方添加用于显示计时器。
注意:如果您擅长CSS,可以将其移至autologout-script模板页面。因此,您可以避免在每个页面中添加它。
包括引导程序或添加自定义CSS。

<span class="badge badge-primary" title="click to keep session alive" id="sessionTimeRemaining" 
    onclick="ajaxSessionRefresh()" style="display:none;">
    <i class="badge badge-danger" id="sessionTimeRemainingBadge" style="float:left">30</i>
     &nbsp; 
     <small>Refresh</small>
     <i class="glyphicon glyphicon-refresh"></i>
</span>

enter image description here

这就是简单的自动注销实现。 您可以从我的github存储库下载工作示例
Autologout using simple servlet example
Autologout using spring-security java configuration example
Autologout using spring-security xml configuration example

逻辑解释


案例1:页面加载
这里的逻辑很简单,页面加载设置计时器的间隔等于maxInactiveInterval。超时后重定向到登录页面。
案例2:跟踪AJAX调用
现在考虑AJAX请求,您可以使用jquery的.ajaxStart()或.ajaxComplete()回调,这样,如果触发了任何ajax请求,您可以重置时间间隔。
案例3:跟踪多个标签页/窗口活动
进行表间通信以同步每个选项卡的状态。在发生更改事件时使用了localStorage。

所需的限制/改进
1.如果最大允许会话数为1,则如果会话是从另一个系统进行的,则AJAX请求将失败。需要处理它以重定向到登录页面。
2.使用ajaxStart()而不是ajaxComplete()在服务器和浏览器之间实现idleTime值的精确同步。

要求
1. jQuery

当前实施方案的替代方案


1.在http响应中设置刷新标题(不适用于AJAX请求)

response.setHeader("Refresh", "60; URL=login.jsp");
  1. 在HTML 中设置元刷新标记(不适用于AJAX请求)
<meta http-equiv="refresh" content="60; url=login.jsp">
  1. 配置活动检查器 通过重复的AJAX请求使会话保持活动状态。跟踪空闲时间并在超时后发出注销请求。
    毫无疑问,这是一个简单逻辑的好人。但我只想提出自己的看法。
    • 对性能的影响,如果每分钟发出2个请求以保持会话活动和5万活跃用户。每分钟10万个请求。
    • 选项卡间通信如果两个选项卡都打开,则一个选项卡正在接收活动,而另一个选项卡未接收活动,即使其他选项卡中存在活动,该选项卡也会触发注销请求并使会话无效。 (但可以处理)
    • 强制注销方法。这是客户端主导着服务器,使会话无效。