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

发布于 2024-08-16 16:13:57 字数 113 浏览 2 评论 0原文

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

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

我使用的环境是Java EE。

My requirement is to notify the user with a popup saying that the user session is about to time out in x seconds in case user does not perform any activity on the web page.

Addition to this requirement is to decrement the value x seconds dynamically in the popup.

The environment I use is Java EE.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

韵柒 2024-08-23 16:13:57

利用 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 树控制内容并使用另一个 setTimeout() 1 秒来动态更改文本。

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

Make use of HttpSession#getMaxInactiveInterval() and setTimeout(). There's no need for Ajax in this particular purpose, unless you want to postpone the timeout on every client activity (polling).

Basic example:

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

To decrement the time inside the message magically, then instead of the basic alert() you'll need an overlay with a div wherein you have control over the content through HTML DOM tree and make use of another setTimeout() on 1 second to change the text dynamically.

Note that this script has to be served by the JspServlet to get the EL to work. Thus, you need to put the script in the HTML <head> of the JSP page, or if you really want to have all the JS in a separate *.js file, then you need to let the JspServlet handle any *.js requests as well.

完美的未来在梦里 2024-08-23 16:13:57

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

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

I don't think that Java/Java EE will be really helpful here as this need to be handled on the client-side (i.e. using JavaScript). One solution I can think of would be to set a kind of timer that would notify the user a few minutes before the server's timeout.

While googling about this, I found Eric Pascarello's Update User's Session with AJAX blog post (and the reloaded version Updating User Session with Ajax - Round 2) that precisely describes such a solution (and use an XMLHttpRequest to update the session). His Ajax Session Management script is available here.

风吹过旳痕迹 2024-08-23 16:13:57

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

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

自动注销需要非常计算的逻辑。介绍我的自动注销功能实现,具有以下

优点。


1. No extra call/request is used to achieve this. considering performance impact if more than 10k active users and extra calls to achieve auto logout.
2. One line configuration using tag.
3. Works flawlessly even if user opens multiple tab or multiple window.
4. It intimates you before 30 seconds of session invalidation, so if you have filled form and not submitted, you can keep session alive(extend session by one click). So user less likely to loose unsaved data.

用法


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 模板页面。因此,您可以避免在每个页面中添加此内容。
包含 bootstrap 或添加您的自定义 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>
       
     <small>Refresh</small>
     <i class="glyphicon glyphicon-refresh"></i>
</span>

输入图片这里的描述

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

逻辑解释


Case 1: On Page load
Here logic is simple, on page load set timer of interval equlas to maxInactiveInterval. after timeout redirect to login page.
Case 2: Keep track AJAX calls
Now considering AJAX requests, you can use .ajaxStart() or .ajaxComplete() callbacks of jquery so that if any ajax request is fired you can reset the interval.
Case 3: Tracking multi tab/window activity
Intertab communication is done to synchronize state of each tab. Used localStorage on change event.

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

要求
1. Jquery

替代方案与当前实现的比较


1. Setting Refresh header in http response. (Not works for AJAX requests)

response.setHeader("Refresh", "60; URL=login.jsp");
  1. 在 HTML 中设置元刷新标记(不适用于 AJAX 请求)
<meta http-equiv="refresh" content="60; url=login.jsp">
  1. 配置活动检查器
    通过重复的 AJAX 请求保持会话活动。跟踪空闲时间并在超时后发出注销请求。
    毫无疑问,这是一篇逻辑简单的好文章。但我只想写下我的观察结果。

    • 性能影响:如果每分钟发出 2 个请求以保持会话处于活动状态并拥有 5 万个活跃用户。每分钟 10 万个请求。
    • 选项卡间通信 如果打开了两个选项卡,其中一个选项卡正在接收活动,但另一个选项卡未接收活动,则该选项卡会触发注销请求并使会话无效,即使其他选项卡中存在活动也是如此。 (但可以处理)
    • 强制注销方法这是客户端对服务器的控制,使会话失效。

Either it may be simple servlet, spring-mvc or spring-security auto logout is not possible without perfect client side logic.
Considering application will have both type of request

  • AJAX and
  • form submission/page reload

Auto logout needs very calculated logic. Presenting my autologout functionality implementation with following

Advantages.


1. No extra call/request is used to achieve this. considering performance impact if more than 10k active users and extra calls to achieve auto logout.
2. One line configuration using tag.
3. Works flawlessly even if user opens multiple tab or multiple window.
4. It intimates you before 30 seconds of session invalidation, so if you have filled form and not submitted, you can keep session alive(extend session by one click). So user less likely to loose unsaved data.

Usage


1. Include auto logout script in required JSP pages as given below.

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

2. Create a JSP page, autologout-script.jsp and add below code.
Note: No editing/configuring is required

<%@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. Configure session attributes to configuring timeout setting
Note: Configure this after session creation. You can implement HttpSessionListener sessionCreated method and set the following configuration as per your requirement.

session.setMaxInactiveInterval(300);

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

4. Add below html for displaying timer.
Note: it can be moved to autologout-script template page if you are good at CSS. Hence you can avoid to add this in each and every page.
Include bootstrap or add your custom 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>
       
     <small>Refresh</small>
     <i class="glyphicon glyphicon-refresh"></i>
</span>

enter image description here

That is all about a simple auto logout implementation.
You can download working example from my github repository
Autologout using simple servlet example
Autologout using spring-security java configuration example
Autologout using spring-security xml configuration example

Logic Explained


Case 1: On Page load
Here logic is simple, on page load set timer of interval equlas to maxInactiveInterval. after timeout redirect to login page.
Case 2: Keep track AJAX calls
Now considering AJAX requests, you can use .ajaxStart() or .ajaxComplete() callbacks of jquery so that if any ajax request is fired you can reset the interval.
Case 3: Tracking multi tab/window activity
Intertab communication is done to synchronize state of each tab. Used localStorage on change event.

Limitations/Improvements required
1. If maximum allowed session is one, if session is taken from another system, AJAX request will fail. It needs to be handled to redirect to login page.
2. Use ajaxStart() instead of ajaxComplete() to have exact sync of idleTime values between server and browser.

Requirements
1. Jquery

Alternatives to current implementation compared


1. Setting Refresh header in http response. (Not works for AJAX requests)

response.setHeader("Refresh", "60; URL=login.jsp");
  1. Setting meta refresh tag in HTML (Not works for AJAX requests)
<meta http-equiv="refresh" content="60; url=login.jsp">
  1. Configuring Activity checker
    Keeps session alive by repeated AJAX request. Tracks idle time and makes logout request after timeout.
    No doubt it is a good one with simple logic. But i want to just ink my observations.

    • Performance impact if 2 requests are made per minute to keep session alive and 50k active users. 100k requests per minute.
    • Intertab communication If two tabs are open, one tab is receiving activity but other tab is not receiving activity, that tab fires logout request and invalidate session even though activity is present in other tab. (But can be handled)
    • Force logout approach It is a client is dominated over server to invalidate session.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文