9

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

除了这个要求是在弹出窗口中动态减少 x 秒的值。

我使用的环境是 Java EE。

4

3 回答 3

13

利用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>

要神奇地减少消息中的时间,那么alert()您需要一个带有 div 的叠加层,而不是基本的,您可以在其中通过 HTML DOM 树控制内容,并setTimeout()在 1 秒内使用另一个来动态更改文本。

请注意,此脚本必须由EL 提供服务JspServlet才能使 EL 工作。因此,您需要将脚本放在<head>JSP 页面的 HTML 中,或者如果您真的想将所有 JS 放在一个单独的*.js文件中,那么您还需要让JspServlet处理任何*.js请求。

于 2009-12-31T13:34:45.507 回答
2

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

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

于 2009-12-31T13:11:41.963 回答
0

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

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

自动注销需要非常计算的逻辑。通过以下方式展示我的自动注销功能实现

好处。


1. 不使用额外的调用/请求来实现这一点。如果超过 10k 的活跃用户和额外的调用来实现自动注销,则考虑性能影响。
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>

在此处输入图像描述

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

逻辑解释


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

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

需求
1.jquery

比较当前实现的替代方案


1.在http响应中设置Refresh header 。(不适用于 AJAX 请求)

response.setHeader("Refresh", "60; URL=login.jsp");
  1. 在 HTML 中设置元刷新标签(不适用于 AJAX 请求)
<meta http-equiv="refresh" content="60; url=login.jsp">
  1. 配置活动检查器 通过重复的 AJAX 请求保持会话活动。跟踪空闲时间并在超时后发出注销请求。
    毫无疑问,这是一部逻辑简单的好作品。但我只想写下我的观察。
    • 如果每分钟发出 2 个请求以保持会话活动和 50k 活跃用户,则会影响性能。每分钟 10 万个请求。
    • 选项卡间通信如果打开了两个选项卡,一个选项卡正在接收活动,但另一个选项卡没有接收活动,即使活动存在于其他选项卡中,该选项卡也会触发注销请求并使会话无效。(但可以处理)
    • 强制注销方法这是客户端控制服务器使会话无效。
于 2019-09-11T01:40:37.267 回答