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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1985250/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 18:49:10  来源:igfitidea点击:

Notify user about session timeout in Java EE

javajspservletsjakarta-eesession-timeout

提问by Eager Learner

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.

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

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

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

The environment I use is Java EE.

我使用的环境是Java EE。

回答by BalusC

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

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

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.

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

Note that this script has to be served by the JspServletto 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 *.jsfile, then you need to let the JspServlethandle any *.jsrequests as well.

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

回答by Pascal Thivent

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.

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

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

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

回答by PraveenKumar Lalasangi

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

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

  • AJAX and
  • form submission/page reload
  • AJAX 和
  • 表单提交/页面重新加载

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

自动注销需要非常计算的逻辑。使用以下内容展示我的自动注销功能实现

Advantages.

好处。



1. 没有使用额外的调用/请求来实现这一点。如果超过 10k 的活跃用户和额外的调用来实现自动注销,则考虑性能影响。


2. 使用标签的一条线路配置。


3. 即使用户打开多个标签或多个窗口也能完美运行。


4. 会话失效前30秒提示您,如果您填写了表单没有提交,您可以保持会话活跃(一键延长会话)。因此用户不太可能丢失未保存的数据。

Usage

用法



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

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

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

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

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

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.

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

在此处输入图片说明

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

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

Logic Explained

逻辑解释



Case 1: On Page load案例 1:页面加载


这里的逻辑很简单,在页面加载时将间隔定时器设置为 maxInactiveInterval。超时后重定向到登录页面。


Case 2: Keep track AJAX calls案例 2:跟踪 AJAX 调用


现在考虑 AJAX 请求,您可以使用 jquery 的 .ajaxStart() 或 .ajaxComplete() 回调,以便在触发任何 ajax 请求时您可以重置间隔。


Case 3: Tracking multi tab/window activity案例 3:跟踪多标签/窗口活动


进行标签间通信以同步每个标签的状态。在更改事件上使用 localStorage。


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.

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

Requirements
1. Jquery

需求
1. jQuery

Alternatives to current implementation compared

比较当前实现的替代方案



1. Setting Refresh header在 http 响应中设置刷新标头(Not works for AJAX requests)(不适用于 AJAX 请求)

response.setHeader("Refresh", "60; URL=login.jsp");
  1. Setting meta refresh tagin HTML (Not works for AJAX requests)
  1. 在 HTML 中设置元刷新标记(不适用于 AJAX 请求)
<meta http-equiv="refresh" content="60; url=login.jsp">
  1. Configuring Activity checkerKeeps 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 impactif 2 requests are made per minute to keep session alive and 50k active users. 100k requests per minute.
    • Intertab communicationIf 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 approachIt is a client is dominated over server to invalidate session.
  1. 配置活动检查器通过重复的 AJAX 请求使会话保持活动状态。跟踪空闲时间并在超时后提出注销请求。
    毫无疑问,这是一本逻辑简单的好书。但我只想写下我的观察。
    • 如果每分钟发出 2 个请求以保持会话活动和 50k 活跃用户,则性能影响。每分钟 10 万个请求。
    • Intertab 通信如果两个选项卡打开,一个选项卡正在接收活动,而另一个选项卡没有接收活动,即使其他选项卡中存在活动,该选项卡也会触发注销请求并使会话无效。(但可以处理)
    • 强制注销方法客户端控制服务器使会话无效。