Java 会话过期/超时后 JSP 自动重定向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3915787/
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-08-14 06:49:30  来源:igfitidea点击:

JSP Automatic Redirect After Session Expire/Timeout

javajspsession-timeout

提问by user473445

Is there any way to detect session timeout without (user interaction)*, and redirect it to some page; i.e. if there is no activity on page @ specific duration; server detects it and redirect it automatically on some other.

有没有办法在没有(用户交互)*的情况下检测会话超时,并将其重定向到某个页面;即如果页面@特定持续时间没有活动;服务器检测到它并自动将其重定向到其他一些。

By user user interaction I mean; there is a way to detect session timeout when user clicks on something, then some request goes to server and then server checks if current user session is expired or not.

我的意思是用户交互;有一种方法可以在用户单击某些内容时检测会话超时,然后某些请求会发送到服务器,然后服务器会检查当前用户会话是否已过期。

What I need here is that we don't inform server anything (or we don't perform any action), but when session expires server detects it automatically and perform required action.

我在这里需要的是我们不通知服务器任何事情(或者我们不执行任何操作),但是当会话到期时服务器会自动检测它并执行所需的操作。

Thanks, Raza

谢谢,拉扎

采纳答案by Sean Patrick Floyd

You can of course do such a thing in JavaScript by implementing a document-wide keyboard and / or mouse listener and a periodical method with a timeout.

您当然可以在 JavaScript 中通过实现文档范围的键盘和/或鼠标侦听器以及具有超时的周期性方法来执行此类操作。

var timeOut = 1000 * 60 * 30; // 30 minutes
var lastActivity = new Date().getTime();
var checkTimeout;
checkTimeOut = function(){
    if(new Date().getTime() > lastActivity + timeOut){
        // redirect to timeout page
    }else{
        window.setTimeout(checkTimeOut, 1000); // check once per second
    }
}

now your global listeners just have to set lastActivity to the current time on everyaction.

现在,您的全局侦听器只需将 lastActivity 设置为每个操作的当前时间。

On re-reading the question, you want to use the actual session timeout from the application server. That's a tough one, because your when you send ajax requests to the server you will actually keep the session from expiring (unless there is a hard limit), so my answer might still be the best way to do it.

重新阅读问题时,您希望使用应用程序服务器的实际会话超时。这是一个艰难的问题,因为当您向服务器发送 ajax 请求时,您实际上会阻止会话过期(除非有硬性限制),所以我的回答可能仍然是最好的方法。

回答by malificent

I had somewhat of the same problem so here's how I solved it...

我有一些同样的问题,所以这是我解决它的方法......

Basically I created a session timer on the client side with javascript. I send an ajax call periodically (on a timer that is less than the actual server timeout setting) to keep the session alive on the server.

基本上我用javascript在客户端创建了一个会话计时器。我定期发送一个 ajax 调用(在一个小于实际服务器超时设置的计时器上)以保持会话在服务器上处于活动状态。

Then I created another timer that counts down on the client side (set to the same time as the actual server timeout setting). If that timer expires, then an ajax call is made to the server that runs session.invalidate() and then forwards to the login page. This timer is reset every time there is some action that should keep the session alive (i.e. mouse click, keypress, etc.)

然后我创建了另一个在客户端倒计时的计时器(设置为与实际服务器超时设置相同的时间)。如果该计时器到期,则会对运行 session.invalidate() 的服务器进行 ajax 调用,然后转发到登录页面。每次有一些应该使会话保持活动状态的操作(即鼠标单击、按键等)时,都会重置此计时器

回答by Jimmy Leo

If the requirement is to just redirect to the login page (or any other page) after the session timed out, this is how I've tried to implement it:

如果要求只是在会话超时后重定向到登录页面(或任何其他页面),这就是我尝试实现它的方式:

Include the following scriptlet to ALL pages that requires login

在所有需要登录的页面中包含以下脚本

<%
int timeout = session.getMaxInactiveInterval();
response.setHeader("Refresh", timeout + "; URL = login.jsp");
%>

This way any page that requires login will refresh/redirect to login.jsp (change it your desired url) after the session timed out

这样,任何需要登录的页面都会在会话超时后刷新/重定向到 login.jsp(将其更改为您想要的 url)

OR (to avoid missing any pages)

或(避免遗漏任何页面)

You can actually write it in a separate file (timedoutRedirect.jsp) and include it as a header to all pages that requires login using "JSP property group" (in web.xml)

您实际上可以将它写在一个单独的文件 (timedoutRedirect.jsp) 中,并将其作为标题包含在所有需要使用“JSP 属性组”登录的页面中(在 web.xml 中)

<jsp-property-group>
        <display-name>all jsp</display-name>
        <url-pattern>/users/*</url-pattern>
        <include-prelude>/timedoutRedirect.jsp</include-prelude>           
</jsp-property-group>

(you may have to adjust the prelude url to your project specifications)

(您可能需要根据您的项目规范调整前奏网址)

回答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 通信如果两个选项卡打开,一个选项卡正在接收活动,而另一个选项卡未接收活动,即使其他选项卡中存在活动,该选项卡也会触发注销请求并使会话无效。(但可以处理)
    • 强制注销方法客户端控制服务器使会话无效。