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

时间:2010-10-12 14:35:17

标签: java jsp session-timeout

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

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

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

谢谢, 拉扎

4 个答案:

答案 0 :(得分:7)

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

将以下scriptlet包含在需要登录的所有页面

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

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

OR(避免错过任何页面)

您实际上可以将其写在单独的文件(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>

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

答案 1 :(得分:3)

当然,您可以通过实现文档范围的键盘和/或鼠标侦听器以及带有超时的定期方法在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
    }
}

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

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

答案 2 :(得分:0)

我有一些相同的问题,所以这就是我如何解决它......

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

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

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